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 142 - .gitlab-ci/ci-cmake-build.sh {{- make_cmake_args(job.cmake_defines) }} 143 143 {%- if job.pahole %} 144 144 145 - - src/xrt/ipc/shared/proto.py src/xrt/ipc/shared/proto.json structs.txt 146 145 - 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 %} 146 + - pahole --sizes --class_name file://build/ipc-structs.txt build/src/xrt/targets/openxr/libopenxr_monado.so > "{{ job.name}}/ipc-sizes.txt"{% endif %} 148 147 149 148 {#- gradle builds -#} 150 149 {%- elif "android" in job.name %}
+3 -3
.gitlab-ci/templates/include.win_containers.yml
··· 1 1 # {#- included by .gitlab-ci.yml.jinja #} 2 2 # {#- SPDX-License-Identifier: CC0-1.0 #} 3 - # {#- SPDX-FileCopyrightText: 2018-2022 Collabora, Ltd. and the Monado contributors #} 3 + # {#- SPDX-FileCopyrightText: 2018-2025 Collabora, Ltd. and the Monado contributors #} 4 4 5 5 ### 6 6 # Windows container-related jobs (prep and usage) ··· 9 9 inherit: 10 10 default: false 11 11 variables: 12 - MONADO_WIN_BASE_TAG: "20250418.0" 13 - MONADO_WIN_MAIN_TAG: "20250418.0" 12 + MONADO_WIN_BASE_TAG: "20251127.3" 13 + MONADO_WIN_MAIN_TAG: "20251127.3" 14 14 MONADO_BASE_IMAGE_PATH: "win2022/vs2022_base" 15 15 MONADO_MAIN_IMAGE_PATH: "win2022/vs2022" 16 16
+3 -3
.gitlab-ci/windows/monado_deps_build.ps1
··· 1 1 # Copyright 2019-2022, Mesa contributors 2 - # Copyright 2022, Collabora, Ltd. 2 + # Copyright 2022-2025, Collabora, Ltd. 3 3 # SPDX-License-Identifier: MIT 4 4 # Based on https://gitlab.freedesktop.org/mesa/mesa/-/blob/8396df5ad90aeb6ab2267811aba2187954562f81/.gitlab-ci/windows/mesa_deps_build.ps1 5 5 6 - $VulkanRTVersion = "1.3.283.0" 6 + $VulkanRTVersion = "1.4.328.1" 7 7 8 8 # Download new TLS certs from Windows Update 9 9 Get-Date ··· 28 28 Get-Date 29 29 Write-Host "Installing Vulkan runtime components" 30 30 $VulkanInstaller = "C:\VulkanRTInstaller.exe" 31 - Invoke-WebRequest -Uri "https://sdk.lunarg.com/sdk/download/$VulkanRTVersion/windows/VulkanRT-$VulkanRTVersion-Installer.exe" -OutFile "$VulkanInstaller" 31 + Invoke-WebRequest -Uri "https://sdk.lunarg.com/sdk/download/$VulkanRTVersion/windows/VulkanRT-X64-$VulkanRTVersion-Installer.exe" -OutFile "$VulkanInstaller" 32 32 Start-Process -NoNewWindow -Wait "$VulkanInstaller" -ArgumentList "/S" 33 33 if (!$?) { 34 34 Write-Host "Failed to install Vulkan runtime components"
+2 -2
.gitlab-ci/windows/monado_deps_vs2022.ps1
··· 1 1 # Copyright 2019-2022, Mesa contributors 2 - # Copyright 2022, Collabora, Ltd. 2 + # Copyright 2022-2025, Collabora, Ltd. 3 3 # SPDX-License-Identifier: MIT 4 4 # Based on https://gitlab.freedesktop.org/mesa/mesa/-/blob/8396df5ad90aeb6ab2267811aba2187954562f81/.gitlab-ci/windows/mesa_deps_vs2019.ps1 5 5 ··· 29 29 "--add" 30 30 "Microsoft.VisualStudio.Component.Windows10SDK" 31 31 "--add" 32 - "Microsoft.VisualStudio.Component.Windows11SDK.22000" 32 + "Microsoft.VisualStudio.Component.Windows11SDK.26100" 33 33 "--add" 34 34 "Component.Microsoft.Windows.CppWinRT" 35 35 "--add"
+4 -6
.gitlab-ci.yml
··· 56 56 inherit: 57 57 default: false 58 58 variables: 59 - MONADO_WIN_BASE_TAG: "20250418.0" 60 - MONADO_WIN_MAIN_TAG: "20250418.0" 59 + MONADO_WIN_BASE_TAG: "20251127.3" 60 + MONADO_WIN_MAIN_TAG: "20251127.3" 61 61 MONADO_BASE_IMAGE_PATH: "win2022/vs2022_base" 62 62 MONADO_MAIN_IMAGE_PATH: "win2022/vs2022" 63 63 ··· 369 369 370 370 - .gitlab-ci/prebuild.sh 371 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 372 - 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" 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" 375 374 - cd build && ctest --output-on-failure 376 375 artifacts: 377 376 paths: ··· 408 407 409 408 - .gitlab-ci/prebuild.sh 410 409 - .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 410 - 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" 411 + - pahole --sizes --class_name file://build/ipc-structs.txt build/src/xrt/targets/openxr/libopenxr_monado.so > "debian:cmake:32bit/ipc-sizes.txt" 414 412 - cd build && ctest --output-on-failure 415 413 artifacts: 416 414 paths:
+2
CMakeLists.txt
··· 58 58 include(OptionWithDeps) 59 59 include(SPIR-V) 60 60 include(GNUInstallDirs) 61 + include(MergeJSON) 61 62 if(NOT GIT_DESC) 62 63 include(GetGitRevisionDescription) 63 64 git_describe(GIT_DESC "--always") ··· 367 368 option(XRT_FEATURE_OPENXR_ACTIVE_ACTION_SET_PRIORITY "Enable XR_EXT_active_action_set_priority" ON) 368 369 option(XRT_FEATURE_OPENXR_BODY_TRACKING_FB "Enable XR_FB_body_tracking" OFF) 369 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) 370 372 option(XRT_FEATURE_OPENXR_FACE_TRACKING2_FB "Enable XR_FB_face_tracking2" OFF) 371 373 option(XRT_FEATURE_OPENXR_FACIAL_TRACKING_HTC "Enable XR_HTC_facial_tracking" OFF) 372 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 14 function(spirv_shaders ret) 15 15 set(options) 16 16 set(oneValueArgs SPIRV_VERSION) 17 - set(multiValueArgs SOURCES) 17 + set(multiValueArgs SOURCES DEPENDS) 18 18 cmake_parse_arguments(_spirvshaders "${options}" "${oneValueArgs}" 19 19 "${multiValueArgs}" ${ARGN}) 20 20 ··· 30 30 add_custom_command( 31 31 OUTPUT ${HEADER} 32 32 COMMAND ${GLSLANGVALIDATOR_COMMAND} -V --target-env spirv${_spirvshaders_SPIRV_VERSION} ${GLSL} --vn ${IDENTIFIER} -o ${HEADER} 33 - DEPENDS ${GLSL}) 33 + DEPENDS ${GLSL} ${_spirvshaders_DEPENDS}) 34 34 list(APPEND HEADERS ${HEADER}) 35 35 endforeach() 36 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 1 --- 2 + - mr.2615 2 3 - mr.2616 4 + - mr.2620 3 5 --- 4 6 5 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 1 + gui: Refactor GUI state tracker into a base that can be more easily reused 2 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 76 ['XR_EXT_samsung_odyssey_controller', 'XRT_FEATURE_OPENXR_INTERACTION_WINMR'], 77 77 ['XR_EXT_user_presence', 'XRT_FEATURE_OPENXR_USER_PRESENCE'], 78 78 # Vendor extensions, sorted alphabetically. 79 + ['XR_ANDROID_face_tracking', 'XRT_FEATURE_OPENXR_FACE_TRACKING_ANDROID'], 79 80 ['XR_BD_controller_interaction', 'XRT_FEATURE_OPENXR_INTERACTION_BYTEDANCE'], 80 81 ['XR_FB_body_tracking', 'XRT_FEATURE_OPENXR_BODY_TRACKING_FB'], 81 82 ['XR_FB_composition_layer_alpha_blend', 'XRT_FEATURE_OPENXR_LAYER_FB_ALPHA_BLEND'], ··· 105 106 ['XR_HTCX_vive_tracker_interaction', 'ALWAYS_DISABLED'], 106 107 ['XR_MNDX_ball_on_a_stick_controller', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'], 107 108 ['XR_MNDX_blubur_s1', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'], 108 - ['XR_MNDX_oculus_remote', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'], 109 109 ['XR_MNDX_egl_enable', 'XR_USE_PLATFORM_EGL'], 110 110 ['XR_MNDX_force_feedback_curl', 'XRT_FEATURE_OPENXR_FORCE_FEEDBACK_CURL'], 111 111 ['XR_MNDX_hydra', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'], 112 + ['XR_MNDX_oculus_remote', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'], 112 113 ['XR_MNDX_psvr2_interaction', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'], 113 114 ['XR_MNDX_system_buttons', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'], 114 115 ['XR_MNDX_xdev_space', 'XRT_FEATURE_OPENXR_XDEV_SPACE'],
+1
scripts/mapping.imp
··· 40 40 { symbol: ["XRT_FEATURE_OPENXR_BODY_TRACKING_FULL_BODY_META", "public", "\"xrt/xrt_config_build.h\"", "public"] }, 41 41 { symbol: ["XRT_FEATURE_OPENXR_DEBUG_UTILS", "public", "\"xrt/xrt_config_build.h\"", "public"] }, 42 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"] }, 43 44 { symbol: ["XRT_FEATURE_OPENXR_FACE_TRACKING2_FB", "public", "\"xrt/xrt_config_build.h\"", "public"] }, 44 45 { symbol: ["XRT_FEATURE_OPENXR_FACIAL_TRACKING_HTC", "public", "\"xrt/xrt_config_build.h\"", "public"] }, 45 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 14 15 15 // clang-format off 16 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 17 enum xrt_input_name 26 18 xrt_input_name_enum(const char *input) 27 19 { 28 20 $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 21 } 39 22 40 23 enum xrt_output_name
-6
src/xrt/auxiliary/bindings/b_generated_bindings_helpers.h
··· 17 17 extern "C" { 18 18 #endif 19 19 20 - const char * 21 - xrt_input_name_string(enum xrt_input_name input); 22 - 23 20 enum xrt_input_name 24 21 xrt_input_name_enum(const char *input); 25 - 26 - const char * 27 - xrt_output_name_string(enum xrt_output_name output); 28 22 29 23 enum xrt_output_name 30 24 xrt_output_name_enum(const char *output);
-12
src/xrt/auxiliary/bindings/bindings.py
··· 588 588 inputs.add("XRT_INPUT_HT_CONFORMING_RIGHT") 589 589 inputs.add("XRT_INPUT_GENERIC_TRACKER_POSE") 590 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 591 xrt_input_name_enum_content = '\n'.join( 597 592 [f'\tif(strcmp("{input}", input) == 0) return {input};' for input in sorted(inputs)] 598 593 ) 599 594 xrt_input_name_enum_content += f'\n\treturn XRT_INPUT_GENERIC_TRACKER_POSE;' 600 595 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 596 xrt_output_name_enum_content = '\n'.join( 607 597 [f'\tif(strcmp("{output}", output) == 0) return {output};' for output in sorted(outputs)] 608 598 ) ··· 614 604 615 605 with open(file, "w") as f: 616 606 filled = src.substitute( 617 - xrt_input_name_string_switch=xrt_input_name_string_switch, 618 607 xrt_input_name_enum_content=xrt_input_name_enum_content, 619 - xrt_output_name_string_switch=xrt_output_name_string_switch, 620 608 xrt_output_name_enum_content=xrt_output_name_enum_content 621 609 ) 622 610 f.write(filled)
-1
src/xrt/auxiliary/d3d/d3d_d3d12_allocator.hpp
··· 31 31 * @param xsci Swapchain create info: note that the format is assumed to be a DXGI_FORMAT (conversion to typeless is 32 32 * automatic) 33 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 34 * @param[out] out_images A vector that will be cleared and populated with the images. 36 35 * @param[out] out_handles A vector that will be cleared and populated with the corresponding native handles. 37 36 * @param[out] out_image_mem_size The image memory allocation size in bytes
+21
src/xrt/auxiliary/math/m_api.h
··· 18 18 19 19 #include "xrt/xrt_defines.h" 20 20 21 + #include "math/m_mathinclude.h" 22 + 21 23 #ifdef __cplusplus 22 24 extern "C" { 23 25 #endif ··· 74 76 * @ingroup aux_math 75 77 */ 76 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 77 98 78 99 79 100 /*
+37 -33
src/xrt/auxiliary/math/m_relation_history.cpp
··· 183 183 } 184 184 } 185 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) 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) 191 193 { 194 + assert(dt != 0.0f); 192 195 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 - }; 196 + enum xrt_space_relation_flags shared_flags = 197 + (enum xrt_space_relation_flags)(old_relation.relation_flags & new_relation.relation_flags); 198 198 199 - float dt = (float)time_ns_to_s(timestamp - last_time_ns); 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); 200 202 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); 203 + out_linear_velocity = (new_relation.pose.position - old_relation.pose.position) / dt; 204 + } 212 205 213 - outf = (enum xrt_space_relation_flags)(outf | XRT_SPACE_RELATION_LINEAR_VELOCITY_VALID_BIT); 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); 214 209 215 - out_relation->linear_velocity = (in_relation->pose.position - last_relation.pose.position) / dt; 210 + math_quat_finite_difference(&old_relation.pose.orientation, &new_relation.pose.orientation, dt, 211 + &out_angular_velocity); 216 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); 217 222 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); 223 + struct xrt_space_relation final_relation = *in_relation; 221 224 222 - outf = (enum xrt_space_relation_flags)(outf | XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT); 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); 223 229 224 - math_quat_finite_difference(&last_relation.pose.orientation, &in_relation->pose.orientation, dt, 225 - &out_relation->angular_velocity); 230 + m_relation_history_estimate_motion(last_relation, *in_relation, dt, final_relation.linear_velocity, 231 + final_relation.angular_velocity, final_relation.relation_flags); 226 232 } 227 233 228 - out_relation->pose = in_relation->pose; 229 - 230 - return true; 234 + return m_relation_history_push(rh, &final_relation, timestamp); 231 235 } 232 236 233 237 bool
+15 -17
src/xrt/auxiliary/math/m_relation_history.h
··· 63 63 m_relation_history_push(struct m_relation_history *rh, struct xrt_space_relation const *in_relation, int64_t timestamp); 64 64 65 65 /*! 66 - * Interpolates or extrapolates to the desired timestamp. 66 + * Pushes a new pose to the history, estimating linear and angular velocity based on the previous entry. 67 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. 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 70 71 * 71 72 * @public @memberof m_relation_history 72 73 */ 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); 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); 77 78 78 79 /*! 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). 80 + * Interpolates or extrapolates to the desired timestamp. 81 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. 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. 85 84 * 86 85 * @public @memberof m_relation_history 87 86 */ 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); 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); 93 91 94 92 /*! 95 93 * Get the latest report in the buffer, if any.
+4 -4
src/xrt/auxiliary/tracking/t_tracker_slam.cpp
··· 407 407 { 408 408 t.timing.enabled = false; 409 409 410 - u_var_add_ro_ftext(&t, "\n%s", "Tracker timing"); 410 + u_var_add_ro_raw_text(&t, "\nTracker timing", "Tracker timing"); 411 411 412 412 // Setup toggle button 413 413 static const char *msg[2] = {"[OFF] Enable timing", "[ON] Disable timing"}; ··· 527 527 { 528 528 t.features.enabled = false; 529 529 530 - u_var_add_ro_ftext(&t, "\n%s", "Tracker features"); 530 + u_var_add_ro_raw_text(&t, "\nTracker features", "Tracker features"); 531 531 532 532 // Setup toggle button 533 533 static const char *msg[2] = {"[OFF] Enable features info", "[ON] Disable features info"}; ··· 695 695 static void 696 696 gt_ui_setup(TrackerSlam &t) 697 697 { 698 - u_var_add_ro_ftext(&t, "\n%s", "Tracker groundtruth"); 698 + u_var_add_ro_raw_text(&t, "\nTracker groundtruth", "Tracker groundtruth"); 699 699 t.gt.diff_ui.values.data = t.gt.diffs_mm; 700 700 t.gt.diff_ui.values.length = UI_GTDIFF_POSE_COUNT; 701 701 t.gt.diff_ui.values.index_ptr = &t.gt.diff_idx; ··· 1081 1081 } 1082 1082 1083 1083 u_var_add_gui_header(&t, NULL, "Stats"); 1084 - u_var_add_ro_ftext(&t, "\n%s", "Record to CSV files"); 1084 + u_var_add_ro_raw_text(&t, "\nRecord to CSV files", "Record to CSV files"); 1085 1085 u_var_add_bool(&t, &t.slam_traj_writer->enabled, "Record tracked trajectory"); 1086 1086 u_var_add_bool(&t, &t.pred_traj_writer->enabled, "Record predicted trajectory"); 1087 1087 u_var_add_bool(&t, &t.filt_traj_writer->enabled, "Record filtered trajectory");
+2
src/xrt/auxiliary/util/CMakeLists.txt
··· 29 29 u_deque.h 30 30 u_device.c 31 31 u_device.h 32 + u_device_ni.c 33 + u_device_ni.h 32 34 u_distortion.c 33 35 u_distortion.h 34 36 u_distortion_mesh.c
+2 -1
src/xrt/auxiliary/util/u_config_json.c
··· 14 14 #include "util/u_file.h" 15 15 #include "util/u_json.h" 16 16 #include "util/u_debug.h" 17 + #include "util/u_pretty_print.h" 17 18 18 19 #include "u_config_json.h" 19 20 ··· 504 505 505 506 cJSON_AddItemToObject(entry, "offset", make_pose(&overrides[i].offset)); 506 507 507 - const char *input_name_string = xrt_input_name_string(overrides[i].input_name); 508 + const char *input_name_string = u_str_xrt_input_name(overrides[i].input_name); 508 509 cJSON_AddStringToObject(entry, "xrt_input_name", input_name_string); 509 510 510 511 cJSON_AddItemToArray(o, entry);
+51 -58
src/xrt/auxiliary/util/u_device.c
··· 11 11 */ 12 12 13 13 #include "util/u_device.h" 14 + #include "util/u_device_ni.h" 14 15 #include "util/u_logging.h" 15 16 #include "util/u_misc.h" 16 17 #include "util/u_visibility_mask.h" ··· 461 462 u_device_get_view_poses(struct xrt_device *xdev, 462 463 const struct xrt_vec3 *default_eye_relation, 463 464 int64_t at_timestamp_ns, 465 + enum xrt_view_type view_type, 464 466 uint32_t view_count, 465 467 struct xrt_space_relation *out_head_relation, 466 468 struct xrt_fov *out_fovs, ··· 510 512 511 513 /* 512 514 * 513 - * Not implemented function helpers. 515 + * Helper function to fill in defaults. 514 516 * 515 517 */ 516 518 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) 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) 525 523 { 526 - E(get_hand_tracking); 527 - return XRT_ERROR_NOT_IMPLEMENTED; 528 - } 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 + } 529 528 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 - } 529 + if (destroy_fn == NULL) { 530 + U_LOG_E("Got destroy_fn == NULL!"); 531 + assert(destroy_fn != NULL); 532 + } 536 533 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 - } 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; 557 539 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 - } 540 + // This must be implemented by the driver. 541 + xdev->get_tracked_pose = get_tracked_pose_fn; 567 542 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 - } 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; 574 570 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; 571 + // This must be implemented by the driver. 572 + xdev->destroy = destroy_fn; 580 573 }
+22 -56
src/xrt/auxiliary/util/u_device.h
··· 171 171 u_device_get_view_poses(struct xrt_device *xdev, 172 172 const struct xrt_vec3 *default_eye_relation, 173 173 int64_t at_timestamp_ns, 174 + enum xrt_view_type view_type, 174 175 uint32_t view_count, 175 176 struct xrt_space_relation *out_head_relation, 176 177 struct xrt_fov *out_fovs, ··· 205 206 206 207 /* 207 208 * 208 - * Not implemented function helpers. 209 + * Helper function to fill in defaults. 209 210 * 210 211 */ 211 212 212 213 /*! 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. 214 + * Function pointer type for the device's get_tracked_pose function. 248 215 * 249 216 * @ingroup aux_util 250 217 */ 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); 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); 254 222 255 223 /*! 256 - * Not implemented function for @ref xrt_device::get_visibility_mask. 224 + * Function pointer type for the device's destroy function. 257 225 * 258 226 * @ingroup aux_util 259 227 */ 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); 228 + typedef void (*u_device_destroy_function_t)(struct xrt_device *xdev); 265 229 266 230 /*! 267 - * Not implemented function for @ref xrt_device::is_form_factor_available. 231 + * Populate the device's function pointers with default implementations. 268 232 * 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. 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. 276 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. 277 242 * @ingroup aux_util 278 243 */ 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 - 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); 282 248 283 249 #ifdef __cplusplus 284 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 32 struct xrt_quat q[HAND_SIM_NUM_FINGERS][HAND_SIM_NUM_ORIENTATIONS_IN_FINGER]; 33 33 }; 34 34 35 - #define DEG_TO_RAD(DEG) (DEG * M_PI / 180.) 36 - 37 35 // For debugging. 38 36 #if 0 39 37 #include <iostream>
-2
src/xrt/auxiliary/util/u_hand_tracking.c
··· 20 20 #include "util/u_time.h" 21 21 22 22 23 - #define DEG_TO_RAD(DEG) (DEG * M_PI / 180.) 24 - 25 23 bool 26 24 u_hand_joint_is_metacarpal(enum xrt_hand_joint joint) 27 25 {
+61 -2
src/xrt/auxiliary/util/u_logging.c
··· 1 1 // Copyright 2019-2025, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 74 75 75 76 /* 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 + * 77 110 * Logging sink. 78 111 * 79 112 */ ··· 294 327 int ret = 0; 295 328 296 329 #ifdef XRT_FEATURE_COLOR_LOG 297 - if (isatty(STDERR_FILENO)) { 330 + if (g_log_file == NULL && isatty(STDERR_FILENO)) { 298 331 ret = print_prefix_color(func, level, buf, remaining); 299 332 } else { 300 333 ret = print_prefix_mono(func, level, buf, remaining); ··· 407 440 OutputDebugStringA(storage); 408 441 #endif 409 442 410 - fwrite(storage, printed, 1, stderr); 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 411 453 412 454 #else 413 455 #error "Port needed for logging function" ··· 454 496 u_log(file, line, calling_fn, level, "%s", sink.buffer); 455 497 } 456 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 + 457 507 void 458 508 u_log(const char *file, int line, const char *func, enum u_logging_level level, const char *format, ...) 459 509 { 460 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 + 461 516 va_start(args, format); 462 517 DISPATCH_SINK(file, line, func, level, format, args); 463 518 do_print(file, line, func, level, format, args); ··· 474 529 ...) 475 530 { 476 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 + } 477 536 va_start(args, format); 478 537 DISPATCH_SINK(file, line, func, level, format, args); 479 538 do_print(file, line, func, level, format, args);
+32
src/xrt/auxiliary/util/u_logging.h
··· 1 1 // Copyright 2020-2025, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 68 69 const char *format, 69 70 va_list args, 70 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); 71 83 72 84 /*! 73 85 * For places where you really want printf, prints a new-line. ··· 270 282 u_log_get_global_level(void); 271 283 272 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 + /*! 273 297 * @brief Main non-device-related log implementation function: do not call directly, use a macro that wraps it. 274 298 * 275 299 * This function always logs: level is used for printing or passed to native logging functions. ··· 377 401 const char *calling_fn, 378 402 xrt_result_t xret, 379 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); 380 412 381 413 /*! 382 414 * @}
+86 -52
src/xrt/auxiliary/util/u_pretty_print.c
··· 1 1 // Copyright 2022-2024, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 39 40 case XRT_INPUT_TYPE_HAND_TRACKING: return "HAND_TRACKING"; 40 41 case XRT_INPUT_TYPE_FACE_TRACKING: return "FACE_TRACKING"; 41 42 case XRT_INPUT_TYPE_BODY_TRACKING: return "BODY_TRACKING"; 42 - default: return "<UNKNOWN>"; 43 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>"; 44 57 } 45 58 46 59 void ··· 70 83 71 84 /* 72 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 + * 73 141 * 'Exported' functions. 74 142 * 75 143 */ ··· 112 180 void 113 181 u_pp_xrt_input_name(struct u_pp_delegate dg, enum xrt_input_name name) 114 182 { 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) 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; 120 187 } 121 188 122 - #undef XRT_INPUT_LIST_TO_CASE 123 - 124 189 /* 125 - * No default case so we get warnings of missing entries. 126 190 * Invalid values handled below. 127 191 */ 128 192 ··· 136 200 void 137 201 u_pp_xrt_output_name(struct u_pp_delegate dg, enum xrt_output_name name) 138 202 { 139 - #define XRT_OUTPUT_CASE(NAME) \ 140 - case NAME: DG(#NAME); return 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 + } 141 208 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); 209 + /* 210 + * Invalid values handled below. 211 + */ 148 212 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); 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); 153 216 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 217 + u_pp(dg, "XRT_OUTPUT_0x%04x_%s", id, str); 185 218 } 186 219 187 220 void ··· 234 267 case XRT_OPERATION_CANCELLED: DG("XRT_OPERATION_CANCELLED"); return; 235 268 case XRT_ERROR_FUTURE_RESULT_NOT_READY: DG("XRT_ERROR_FUTURE_RESULT_NOT_READY"); return; 236 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; 237 271 } 238 272 // clang-format on 239 273
+43
src/xrt/auxiliary/util/u_pretty_print.h
··· 29 29 * they can easily be chained together to form a debug message printing out 30 30 * various information. Most of the final logging functions in Monado inserts a 31 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. 32 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 + 33 76 34 77 /*! 35 78 * Function prototype for receiving pretty printed strings.
+1 -1
src/xrt/auxiliary/util/u_sink_converter.c
··· 1071 1071 sum += xf->data[(((y * 2) + 1) * xf->stride) + (x * 2)]; 1072 1072 sum += xf->data[(((y * 2) + 1) * xf->stride) + (x * 2) + 1]; 1073 1073 1074 - converted->data[(y * converted->stride) + x] = sum / 4; 1074 + converted->data[(y * converted->stride) + x] = (uint8_t)(sum / 4); 1075 1075 } 1076 1076 } 1077 1077
+132 -18
src/xrt/auxiliary/util/u_space_overseer.c
··· 1 1 // Copyright 2023, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 42 43 U_SPACE_TYPE_POSE, 43 44 U_SPACE_TYPE_OFFSET, 44 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, 45 53 }; 46 54 47 55 /*! ··· 330 338 m_relation_chain_push_relation(xrc, &xsr); 331 339 } break; 332 340 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. 341 + case U_SPACE_TYPE_ROOT: return; // Stops the traversing. 342 + case U_SPACE_TYPE_ATTACHABLE: break; // No-op 334 343 } 335 344 336 345 // Please tail-call optimise this miss compiler. ··· 352 361 case U_SPACE_TYPE_NULL: break; 353 362 case U_SPACE_TYPE_POSE: break; 354 363 case U_SPACE_TYPE_OFFSET: break; 355 - case U_SPACE_TYPE_ROOT: return; // Stops the traversing. 364 + case U_SPACE_TYPE_ROOT: return; // Stops the traversing. 365 + case U_SPACE_TYPE_ATTACHABLE: break; // No-op 356 366 } 357 367 358 368 // Can't tail-call optimise this one :( ··· 371 381 } break; 372 382 case U_SPACE_TYPE_OFFSET: m_relation_chain_push_inverted_pose_if_not_identity(xrc, &space->offset.pose); break; 373 383 case U_SPACE_TYPE_ROOT: assert(false); // Should not get here. 384 + case U_SPACE_TYPE_ATTACHABLE: break; // No-op 374 385 } 375 386 } 376 387 ··· 469 480 470 481 // Created with one reference. 471 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; 472 542 } 473 543 474 544 ··· 1033 1103 return xret; 1034 1104 } 1035 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 + 1036 1160 static void 1037 1161 destroy(struct xrt_space_overseer *xso) 1038 1162 { ··· 1089 1213 uso->base.set_tracking_origin_offset = set_tracking_origin_offset; 1090 1214 uso->base.get_reference_space_offset = get_reference_space_offset; 1091 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; 1092 1218 uso->base.destroy = destroy; 1093 1219 uso->broadcast = broadcast; 1094 1220 ··· 1117 1243 bool root_is_unbounded, 1118 1244 bool per_app_local_spaces) 1119 1245 { 1120 - struct xrt_space *root = uso->base.semantic.root; // Convenience 1121 1246 uso->per_app_local_spaces = per_app_local_spaces; 1122 1247 1248 + // Add all devices to the space overseer. 1123 1249 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); 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); 1137 1253 } 1138 - 1139 - u_space_overseer_link_space_to_device(uso, xs, xdev); 1140 1254 } 1141 1255 1142 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 1 // Copyright 2019-2024, Collabora, Ltd. 2 + // Copyright 2024-2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 83 84 //! Pointer that will be passed to the function as its only argument 84 85 void *ptr; 85 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 + 86 94 //! Button text, use var `name` if zeroed 87 95 char label[64]; 88 96 ··· 229 237 U_VAR_KIND_NATIVE_IMAGES_DEBUG, 230 238 U_VAR_KIND_LOG_LEVEL, 231 239 U_VAR_KIND_RO_TEXT, 232 - U_VAR_KIND_RO_FTEXT, 240 + U_VAR_KIND_RO_RAW_TEXT, 233 241 U_VAR_KIND_RO_I16, 234 242 U_VAR_KIND_RO_I32, 235 243 U_VAR_KIND_RO_U16, ··· 247 255 U_VAR_KIND_GUI_HEADER, 248 256 U_VAR_KIND_GUI_HEADER_BEGIN, 249 257 U_VAR_KIND_GUI_HEADER_END, 258 + U_VAR_KIND_GUI_SAMELINE, 250 259 U_VAR_KIND_BUTTON, 251 260 U_VAR_KIND_COMBO, 252 261 U_VAR_KIND_HISTOGRAM_F32, ··· 389 398 ADD_FUNC(native_images_debug, struct u_native_images_debug, NATIVE_IMAGES_DEBUG) \ 390 399 ADD_FUNC(log_level, enum u_logging_level, LOG_LEVEL) \ 391 400 ADD_FUNC(ro_text, const char, RO_TEXT) \ 392 - ADD_FUNC(ro_ftext, const char, RO_FTEXT) \ 401 + ADD_FUNC(ro_raw_text, const char, RO_RAW_TEXT) \ 393 402 ADD_FUNC(ro_i16, int16_t, RO_I16) \ 394 403 ADD_FUNC(ro_i32, int32_t, RO_I32) \ 395 404 ADD_FUNC(ro_u16, uint16_t, RO_U16) \ ··· 407 416 ADD_FUNC(gui_header, bool, GUI_HEADER) \ 408 417 ADD_FUNC(gui_header_begin, bool, GUI_HEADER_BEGIN) \ 409 418 ADD_FUNC(gui_header_end, bool, GUI_HEADER_END) \ 419 + ADD_FUNC(gui_sameline, void, GUI_SAMELINE) \ 410 420 ADD_FUNC(button, struct u_var_button, BUTTON) \ 411 421 ADD_FUNC(combo, struct u_var_combo, COMBO) \ 412 422 ADD_FUNC(draggable_f32, struct u_var_draggable_f32, DRAGGABLE_F32) \
+52 -17
src/xrt/auxiliary/util/u_worker.c
··· 1 1 // Copyright 2022, Collabora, Ltd. 2 + // Copyright 2024-2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 94 95 //! Pointer to poll of threads. 95 96 struct u_worker_thread_pool *uwtp; 96 97 97 - //! Number of tasks that is pending or being worked on in this group. 98 - size_t current_submitted_tasks_count; 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; 99 109 100 - //! Number of threads that have been released or newly entered wait. 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 + */ 101 114 size_t released_count; 102 115 103 116 struct ··· 143 156 continue; 144 157 } 145 158 146 - *out_task = p->tasks[i]; 159 + struct task task = p->tasks[i]; 147 160 p->tasks[i] = (struct task){NULL, NULL, NULL}; 161 + 148 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 + 149 168 return; 150 169 } 151 170 ··· 164 183 165 184 p->tasks[i] = (struct task){g, func, data}; 166 185 p->tasks_in_array_count++; 167 - g->current_submitted_tasks_count++; 186 + g->current_tasks_in_array++; 168 187 return; 169 188 } 170 189 ··· 201 220 */ 202 221 203 222 static bool 204 - locked_group_should_enter_wait_loop(struct pool *p, struct group *g) 223 + locked_group_has_tasks_waiting_or_inflight(const struct group *g) 205 224 { 206 - if (g->current_submitted_tasks_count == 0) { 225 + if (g->current_tasks_in_array == 0 && g->current_working_tasks == 0) { 207 226 return false; 208 227 } 209 228 210 - // Enter the loop as a released thread. 211 - g->released_count++; 212 - 213 229 return true; 214 230 } 215 231 ··· 237 253 */ 238 254 239 255 // Tasks available. 240 - if (g->current_submitted_tasks_count > 0) { 256 + if (locked_group_has_tasks_waiting_or_inflight(g)) { 241 257 242 258 // We have been released or newly entered the loop. 243 259 if (g->released_count > 0) { ··· 265 281 locked_group_wake_waiter_if_allowed(struct pool *p, struct group *g) 266 282 { 267 283 // Are there still outstanding tasks? 268 - if (g->current_submitted_tasks_count > 0) { 284 + if (locked_group_has_tasks_waiting_or_inflight(g)) { 269 285 return; 270 286 } 271 287 ··· 343 359 344 360 snprintf(t->name, sizeof(t->name), "%s: Worker", p->prefix); 345 361 U_TRACE_SET_THREAD_NAME(t->name); 362 + os_thread_name(&t->thread, t->name); 346 363 347 364 os_mutex_lock(&p->mutex); 348 365 ··· 373 390 // No longer working. 374 391 p->working_count--; 375 392 376 - // Only now decrement the task count on the owning group. 377 - task.g->current_submitted_tasks_count--; 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); 378 398 379 399 // Wake up any waiter. 380 400 locked_group_wake_waiter_if_allowed(p, task.g); ··· 401 421 XRT_TRACE_MARKER(); 402 422 int ret; 403 423 404 - assert(starting_worker_count < thread_count); 405 - if (starting_worker_count >= thread_count) { 424 + assert(starting_worker_count <= thread_count); 425 + if (starting_worker_count > thread_count) { 406 426 return NULL; 407 427 } 408 428 ··· 532 552 os_mutex_lock(&p->mutex); 533 553 534 554 // Can we early out? 535 - if (!locked_group_should_enter_wait_loop(p, g)) { 555 + if (!locked_group_has_tasks_waiting_or_inflight(g)) { 536 556 os_mutex_unlock(&p->mutex); 537 557 return; 538 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++; 539 574 540 575 // Wait here until all work been started and completed. 541 576 while (locked_group_should_wait(p, g)) {
+12
src/xrt/auxiliary/util/u_worker.hpp
··· 1 1 // Copyright 2022, Collabora, Ltd. 2 + // Copyright 2024-2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 103 104 ~SharedThreadGroup() 104 105 { 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); 106 118 } 107 119 108 120 friend TaskCollection;
-2
src/xrt/auxiliary/vive/vive_poses.c
··· 12 12 #include "math/m_mathinclude.h" 13 13 #include "math/m_api.h" 14 14 15 - #define DEG_TO_RAD(DEG) (DEG * M_PI / 180.) 16 - 17 15 static void 18 16 vive_poses_apply_right_transform(struct xrt_vec3 *out_transform_position, struct xrt_vec3 *out_transform_rotation) 19 17 {
+41 -35
src/xrt/auxiliary/vk/vk_bundle_init.c
··· 241 241 242 242 vk->features.timestamp_compute_and_graphics = pdp.limits.timestampComputeAndGraphics; 243 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; 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; 246 252 247 253 248 254 /* ··· 975 981 return false; 976 982 } 977 983 978 - static bool 984 + static VkResult 979 985 build_device_extensions(struct vk_bundle *vk, 980 986 VkPhysicalDevice physical_device, 981 987 struct u_string_list *required_device_ext_list, ··· 992 998 NULL, // layer_name 993 999 &prop_count, // out_prop_count 994 1000 &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 - } 1001 + VK_CHK_AND_RET(ret, "vk_enumerate_physical_device_extension_properties"); 999 1002 1000 1003 uint32_t required_device_ext_count = u_string_list_get_size(required_device_ext_list); 1001 1004 const char *const *required_device_exts = u_string_list_get_data(required_device_ext_list); ··· 1004 1007 for (uint32_t i = 0; i < required_device_ext_count; i++) { 1005 1008 const char *ext = required_device_exts[i]; 1006 1009 if (!check_extension(vk, props, prop_count, ext)) { 1007 - VK_DEBUG(vk, "VkPhysicalDevice does not support required extension %s", ext); 1010 + VK_ERROR(vk, "VkPhysicalDevice does not support required extension %s", ext); 1008 1011 free(props); 1009 - return false; 1012 + return VK_ERROR_EXTENSION_NOT_PRESENT; 1010 1013 } 1011 1014 VK_DEBUG(vk, "Using required device ext %s", ext); 1012 1015 } ··· 1042 1045 1043 1046 free(props); 1044 1047 1045 - 1046 - return true; 1048 + return VK_SUCCESS; 1047 1049 } 1048 1050 1049 1051 /*! ··· 1325 1327 struct u_string_list *optional_device_ext_list, 1326 1328 const struct vk_device_features *optional_device_features) 1327 1329 { 1330 + struct u_string_list *device_ext_list = NULL; 1328 1331 VkResult ret; 1329 1332 1330 1333 ret = select_physical_device(vk, forced_index); 1331 - if (ret != VK_SUCCESS) { 1332 - return ret; 1333 - } 1334 + VK_CHK_WITH_GOTO(ret, "select_physical_device", err_destroy); 1334 1335 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 - } 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); 1340 1343 1341 1344 1342 1345 /* ··· 1359 1362 if (!vk->has_EXT_global_priority && // 1360 1363 !vk->has_KHR_global_priority && // 1361 1364 global_priority != VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT) { 1362 - return VK_ERROR_NOT_PERMITTED_EXT; 1365 + ret = VK_ERROR_NOT_PERMITTED_EXT; 1366 + goto err_destroy; 1363 1367 } 1364 1368 1365 1369 vk_reset_queues(vk); ··· 1367 1371 struct vk_queue_family main_queue_family = {0}; 1368 1372 if (only_compute) { 1369 1373 ret = find_queue_family(vk, VK_QUEUE_COMPUTE_BIT, &main_queue_family); 1374 + VK_CHK_WITH_GOTO(ret, "find_queue_family", err_destroy); 1370 1375 } else { 1371 1376 ret = find_graphics_queue_family(vk, &main_queue_family); 1372 - } 1373 - 1374 - if (ret != VK_SUCCESS) { 1375 - return ret; 1377 + VK_CHK_WITH_GOTO(ret, "find_graphics_queue_family", err_destroy); 1376 1378 } 1377 1379 1378 1380 assert(main_queue_family.queue_family.queueCount > 0); ··· 1576 1578 1577 1579 ret = vk->vkCreateDevice(vk->physical_device, &device_create_info, NULL, &vk->device); 1578 1580 1581 + // Destroy the list now. 1579 1582 u_string_list_destroy(&device_ext_list); 1580 1583 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; 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; 1587 1588 } 1589 + VK_CHK_WITH_GOTO(ret, "vkCreateDevice", err_destroy); 1588 1590 1589 1591 // Fill in the device features we are interested in. 1590 1592 fill_in_device_features(vk, main_queue.family_index); ··· 1594 1596 1595 1597 // Now setup all of the device specific functions. 1596 1598 ret = vk_get_device_functions(vk); 1597 - if (ret != VK_SUCCESS) { 1598 - goto err_destroy; 1599 - } 1599 + VK_CHK_WITH_GOTO(ret, "vk_get_device_functions", err_destroy); 1600 1600 1601 1601 vk->main_queue = vk_insert_get_queue(vk, &main_queue); 1602 1602 assert(vk->main_queue != NULL); 1603 + 1603 1604 #if defined(VK_KHR_video_encode_queue) 1604 1605 vk->encode_queue = vk_insert_get_queue(vk, &encode_queue); 1605 1606 #endif ··· 1611 1612 return ret; 1612 1613 1613 1614 err_destroy: 1614 - vk->vkDestroyDevice(vk->device, NULL); 1615 - vk->device = NULL; 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); 1616 1622 1617 1623 return ret; 1618 1624 }
+27 -6
src/xrt/auxiliary/vk/vk_helpers.h
··· 200 200 //! Were timeline semaphore requested, available, and enabled? 201 201 bool timeline_semaphore; 202 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 203 //! Was synchronization2 requested, available, and enabled? 210 204 bool synchronization_2; 211 205 ··· 215 209 //! Was KHR_video_maintenance1 requested, available, and enabled? 216 210 bool video_maintenance_1; 217 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; 218 236 219 237 //! Is the GPU a tegra device. 220 238 bool is_tegra; ··· 1077 1095 1078 1096 /*! 1079 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. 1080 1101 * 1081 1102 * @ingroup aux_vk 1082 1103 */
+15 -6
src/xrt/auxiliary/vk/vk_image_allocator.c
··· 184 184 .sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID, 185 185 .externalFormat = a_buffer_format_props.externalFormat, 186 186 }; 187 - CHAIN(format_android); 188 187 189 188 if (image_format == VK_FORMAT_R8G8B8A8_SRGB) { 190 189 // Some versions of Android can't allocate native sRGB, use UNORM and correct gamma later. ··· 192 191 193 192 // https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#VUID-VkImageViewCreateInfo-image-01019 194 193 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); 194 + has_mutable_usage = true; 200 195 201 196 add_format_non_dup(&flh, VK_FORMAT_R8G8B8A8_UNORM); 202 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 + } 203 211 } 204 212 205 213 if (vk_csci_is_format_supported(vk, image_format, info->bits)) { ··· 256 264 // VUID-VkImageCreateInfo-pNext-01974 257 265 if (format_android.externalFormat != 0) { 258 266 create_info.format = VK_FORMAT_UNDEFINED; 267 + CHAIN(format_android); 259 268 } 260 269 #endif 261 270
+21 -5
src/xrt/compositor/client/comp_d3d11_client.cpp
··· 763 763 static void 764 764 client_d3d11_compositor_init_try_timeline_semaphores(struct client_d3d11_compositor *c) 765 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. 766 771 c->timeline_semaphore_value = 1; 772 + 767 773 // See if we can make a "timeline semaphore", also known as ID3D11Fence 768 774 if (!c->xcn->base.create_semaphore || !c->xcn->base.layer_commit_with_semaphore) { 769 775 return; 770 776 } 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)) { 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) { 774 787 D3D_WARN(c, "Native compositor tried but failed to created a timeline semaphore for us."); 775 788 return; 776 789 } 777 790 D3D_INFO(c, "Native compositor created a timeline semaphore for us."); 778 791 792 + // Because importFence throws on failure we use this ref. 779 793 unique_compositor_semaphore_ref timeline_semaphore{xcsem}; 780 794 781 - // try to import and signal 782 - wil::com_ptr<ID3D11Fence> fence = import_fence(*(c->fence_device), timeline_semaphore_handle.get()); 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. 783 799 HRESULT hr = c->fence_context->Signal(fence.get(), c->timeline_semaphore_value); 784 800 if (!SUCCEEDED(hr)) { 785 801 D3D_WARN(c,
+20 -7
src/xrt/compositor/client/comp_d3d12_client.cpp
··· 1 1 // Copyright 2019-2024, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 801 802 } 802 803 struct xrt_layer_data d = *data; 803 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 + } 804 809 // No flip required: D3D12 swapchain image convention matches Vulkan. 805 810 return xrt_comp_layer_projection(&c->xcn->base, xdev, xscn, &d); 806 811 } ··· 1017 1022 static void 1018 1023 client_d3d12_compositor_init_try_timeline_semaphores(struct client_d3d12_compositor *c) 1019 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. 1020 1030 c->timeline_semaphore_value = 1; 1021 1031 1022 1032 // See if we can make a "timeline semaphore", also known as ID3D12Fence ··· 1024 1034 return; 1025 1035 } 1026 1036 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)) { 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) { 1030 1046 D3D_WARN(c, "Native compositor tried but failed to created a timeline semaphore for us."); 1031 1047 return; 1032 1048 } ··· 1038 1054 // Try to import, importFence throws on failure. 1039 1055 wil::com_ptr<ID3D12Fence1> fence = xrt::auxiliary::d3d::d3d12::importFence( // 1040 1056 *(c->device), // 1041 - timeline_semaphore_handle.get()); // 1042 - 1043 - // The fence now owns the handle., importFence throws on failure. 1044 - timeline_semaphore_handle.release(); 1057 + timeline_semaphore_handle_raw); // 1045 1058 1046 1059 // Check flags. 1047 1060 D3D12_FENCE_FLAGS flags = fence->GetCreationFlags();
+189 -19
src/xrt/compositor/client/comp_egl_client.c
··· 200 200 #endif 201 201 } 202 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 + 203 310 static xrt_result_t 204 311 create_context( 205 312 EGLDisplay display, EGLConfig config, EGLContext app_context, EGLint api_type, EGLContext *out_our_context) ··· 207 314 EGLint old_api_type = eglQueryAPI(); 208 315 209 316 eglBindAPI(api_type); 317 + const char *api_string = 318 + api_type == EGL_OPENGL_API ? "opengl" : (api_type == EGL_OPENGL_ES_API ? "opengl_es" : ""); 210 319 211 - size_t attrc = 0; 212 - EGLint attrs[9] = {0}; 213 - 214 - attrs[attrc++] = EGL_CONTEXT_MAJOR_VERSION; 215 - attrs[attrc++] = 3; 216 320 // Panfrost only supports 3.1 217 - attrs[attrc++] = EGL_CONTEXT_MINOR_VERSION; 218 - attrs[attrc++] = 1; 321 + const EGLint major = 3; 322 + const EGLint minor = 1; 219 323 220 - if (api_type == EGL_OPENGL_API) { 221 - attrs[attrc++] = EGL_CONTEXT_OPENGL_PROFILE_MASK; 222 - attrs[attrc++] = EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT; 324 + EGLint image_prio; 325 + if (!eglQueryContext(display, app_context, EGL_CONTEXT_PRIORITY_LEVEL_IMG, &image_prio)) { 326 + image_prio = 0; 223 327 } 224 328 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; 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 + } 230 388 } 231 389 232 - attrs[attrc++] = EGL_NONE; 233 - assert(attrc <= ARRAY_SIZE(attrs)); 390 + assert((unsigned)attrc <= ARRAY_SIZE(attrs)); 234 391 235 - EGLContext our_context = eglCreateContext(display, config, app_context, attrs); 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 + } 236 406 237 407 // Restore old API type. 238 408 if (old_api_type == EGL_NONE) { ··· 240 410 } 241 411 242 412 if (our_context == EGL_NO_CONTEXT) { 243 - EGL_ERROR("eglCreateContext: %s", egl_error_str(eglGetError())); 413 + EGL_ERROR("eglCreateContext (%s): %s", api_string, last_error); 244 414 return XRT_ERROR_OPENGL; 245 415 } 246 416
+27 -11
src/xrt/compositor/main/comp_compositor.c
··· 1031 1031 1032 1032 COMP_DEBUG(c, "Doing init %p", (void *)c); 1033 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); 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); 1036 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; 1037 1048 } 1038 1049 1039 1050 // Do this as early as possible. ··· 1121 1132 struct xrt_system_compositor_info sys_info_storage = {0}; 1122 1133 struct xrt_system_compositor_info *sys_info = &sys_info_storage; 1123 1134 1124 - // Required by OpenXR spec. 1125 - sys_info->max_layers = XRT_MAX_LAYERS; 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); // 1126 1140 sys_info->compositor_vk_deviceUUID = c->settings.selected_gpu_deviceUUID; 1127 1141 sys_info->client_vk_deviceUUID = c->settings.client_gpu_deviceUUID; 1128 1142 sys_info->client_d3d_deviceLUID = c->settings.client_gpu_deviceLUID; ··· 1131 1145 sys_info->supports_fov_mutable = true; 1132 1146 1133 1147 // clang-format off 1134 - uint32_t view_count = xdev->hmd->view_count; 1135 1148 for (uint32_t i = 0; i < view_count; ++i) { 1136 1149 uint32_t w = (uint32_t)(xdev->hmd->views[i].display.w_pixels * scale); 1137 1150 uint32_t h = (uint32_t)(xdev->hmd->views[i].display.h_pixels * scale); 1138 1151 uint32_t w_2 = xdev->hmd->views[i].display.w_pixels * 2; 1139 1152 uint32_t h_2 = xdev->hmd->views[i].display.h_pixels * 2; 1140 1153 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; 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; 1147 1160 } 1148 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. 1149 1165 1150 1166 // If we can add e.g. video pass-through capabilities, we may need to change (augment) this list. 1151 1167 // Just copying it directly right now.
+7 -2
src/xrt/compositor/main/comp_renderer.c
··· 259 259 struct xrt_fov xdev_fovs[XRT_MAX_VIEWS] = XRT_STRUCT_INIT; 260 260 struct xrt_pose xdev_poses[2][XRT_MAX_VIEWS] = XRT_STRUCT_INIT; 261 261 262 - uint64_t scanout_time_ns = 0; 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; 263 266 if (r->c->xdev->hmd->screens[0].scanout_direction == XRT_SCANOUT_DIRECTION_TOP_TO_BOTTOM) { 264 267 scanout_time_ns = r->c->xdev->hmd->screens[0].scanout_time_ns; 265 268 } else if (r->c->xdev->hmd->screens[0].scanout_direction != XRT_SCANOUT_DIRECTION_NONE) { ··· 274 277 r->c->xdev, // 275 278 &default_eye_relation, // 276 279 begin_timestamp_ns, // at_timestamp_ns 280 + view_type, // 277 281 view_count, // 278 282 &head_relation[0], // out_head_relation 279 283 xdev_fovs, // out_fovs 280 - xdev_poses[0]); 284 + xdev_poses[0]); // 281 285 if (xret != XRT_SUCCESS) { 282 286 struct u_pp_sink_stack_only sink; 283 287 u_pp_delegate_t dg = u_pp_sink_stack_only_init(&sink); ··· 292 296 r->c->xdev, // 293 297 &default_eye_relation, // 294 298 end_timestamp_ns, // at_timestamp_ns 299 + view_type, // 295 300 view_count, // 296 301 &head_relation[1], // out_head_relation 297 302 xdev_fovs, // out_fovs
+4
src/xrt/compositor/main/comp_settings.c
··· 10 10 #include "util/u_debug.h" 11 11 #include "comp_settings.h" 12 12 13 + #ifdef XRT_OS_ANDROID 13 14 #define USE_COMPUTE_DEFAULT false 15 + #else 16 + #define USE_COMPUTE_DEFAULT true 17 + #endif 14 18 15 19 // clang-format off 16 20 DEBUG_GET_ONCE_LOG_OPTION(log, "XRT_COMPOSITOR_LOG", U_LOGGING_INFO)
+2 -2
src/xrt/compositor/main/comp_window_direct.c
··· 64 64 COMP_PRINT_MODE(ct->c, "Available Vk modes for direct mode"); 65 65 for (int i = 0; i < mode_count; i++) { 66 66 VkDisplayModePropertiesKHR *props = &mode_properties[i]; 67 - uint16_t width = props->parameters.visibleRegion.width; 68 - uint16_t height = props->parameters.visibleRegion.height; 67 + uint32_t width = props->parameters.visibleRegion.width; 68 + uint32_t height = props->parameters.visibleRegion.height; 69 69 float refresh = (float)props->parameters.refreshRate / 1000.f; 70 70 71 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 1 // Copyright 2019-2024, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 422 423 .fb_face_tracking2_enabled = false, 423 424 .meta_body_tracking_full_body_enabled = false, 424 425 .meta_body_tracking_calibration_enabled = false, 426 + .android_face_tracking_enabled = false, 425 427 }; 426 428 427 429 switch (msc->sessions.state) { ··· 556 558 U_LOG_I("Stopped native session, shutting down."); 557 559 xrt_comp_end_session(xc); 558 560 break; 559 - case MULTI_SYSTEM_STATE_STOPPED: break; 560 - default: assert(false); 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); 561 572 } 562 573 563 574 os_thread_helper_unlock(&msc->oth); ··· 581 592 */ 582 593 583 594 static xrt_result_t 584 - system_compositor_set_state(struct xrt_system_compositor *xsc, struct xrt_compositor *xc, bool visible, bool focused) 595 + system_compositor_set_state( 596 + struct xrt_system_compositor *xsc, struct xrt_compositor *xc, bool visible, bool focused, int64_t timestamp_ns) 585 597 { 586 598 struct multi_system_compositor *msc = multi_system_compositor(xsc); 587 599 struct multi_compositor *mc = multi_compositor(xc); ··· 596 608 xse.type = XRT_SESSION_EVENT_STATE_CHANGE; 597 609 xse.state.visible = visible; 598 610 xse.state.focused = focused; 611 + xse.state.timestamp_ns = timestamp_ns; 599 612 600 613 return multi_compositor_push_event(mc, &xse); 601 614 }
+38 -10
src/xrt/compositor/null/null_compositor.c
··· 268 268 { 269 269 struct xrt_system_compositor_info *sys_info = &c->sys_info; 270 270 271 - // Required by OpenXR spec. 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 + */ 272 278 sys_info->max_layers = XRT_MAX_LAYERS; 273 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 + 274 292 // UUIDs and LUID already set in vk init. 275 293 (void)sys_info->compositor_vk_deviceUUID; 276 294 (void)sys_info->client_vk_deviceUUID; 277 295 (void)sys_info->client_d3d_deviceLUID; 278 296 (void)sys_info->client_d3d_deviceLUID_valid; 279 - uint32_t view_count = xdev->hmd->view_count; 280 297 // clang-format off 281 298 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; 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; 288 305 } 289 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. 290 310 291 311 // Copy the list directly. 292 312 assert(xdev->hmd->blend_mode_count <= XRT_MAX_DEVICE_BLEND_MODES); ··· 436 456 437 457 struct xrt_fov fovs[2] = {0}; 438 458 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); 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); // 441 469 if (xret != XRT_SUCCESS) { 442 470 return xret; 443 471 }
+48 -12
src/xrt/compositor/render/render_interface.h
··· 1 1 // Copyright 2019-2023, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 58 59 #define RENDER_MAX_LAYERS (XRT_MAX_LAYERS) 59 60 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 + /*! 61 68 * Max number of images that can be given at a single time to the layer 62 69 * squasher in a single dispatch. 63 70 */ 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) 71 + #define RENDER_MAX_IMAGES_SIZE (RENDER_MAX_LAYERS * RENDER_CS_MAX_SAMPLERS_PER_VIEW) 66 72 67 73 /*! 68 74 * Maximum number of times that the layer squasher shader can run per ··· 87 93 //! The binding that the shared layer fragment shader has its source on. 88 94 #define RENDER_BINDING_LAYER_SHARED_SRC 1 89 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 90 101 91 102 /* 92 103 * 93 104 * Util functions. 94 105 * 95 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); 96 120 97 121 /*! 98 122 * Create a simplified projection matrix for timewarp. ··· 1207 1231 struct 1208 1232 { 1209 1233 uint32_t value; 1210 - uint32_t padding[3]; 1234 + uint32_t padding[3]; // Padding up to a vec4. 1211 1235 } layer_count; 1212 1236 1213 1237 struct xrt_normalized_rect pre_transform; 1214 1238 struct xrt_normalized_rect post_transforms[RENDER_MAX_LAYERS]; 1215 1239 1216 - //! std140 uvec2, corresponds to enum xrt_layer_type and unpremultiplied alpha. 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 + */ 1217 1245 struct 1218 1246 { 1219 - uint32_t val; 1220 - uint32_t unpremultiplied; 1221 - uint32_t padding[XRT_MAX_VIEWS]; 1222 - } layer_type[RENDER_MAX_LAYERS]; 1247 + uint32_t layer_type; 1248 + uint32_t unpremultiplied_alpha; 1249 + uint32_t _padding0; 1250 + uint32_t _padding1; 1251 + } layer_data[RENDER_MAX_LAYERS]; 1223 1252 1224 - //! Which image/sampler(s) correspond to each layer. 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 + */ 1225 1258 struct 1226 1259 { 1227 - uint32_t images[XRT_MAX_VIEWS]; 1260 + uint32_t color_image_index; 1261 + uint32_t depth_image_index; 1262 + 1228 1263 //! @todo Implement separated samplers and images (and change to samplers[2]) 1229 - uint32_t padding[XRT_MAX_VIEWS]; 1230 - } images_samplers[RENDER_MAX_LAYERS]; 1264 + uint32_t _padding0; 1265 + uint32_t _padding1; 1266 + } image_info[RENDER_MAX_LAYERS]; 1231 1267 1232 1268 //! Shared between cylinder and equirect2. 1233 1269 struct xrt_matrix_4x4 mv_inverse[RENDER_MAX_LAYERS];
+1 -1
src/xrt/compositor/render/render_resources.c
··· 543 543 r->compute.ubo_binding = 3; 544 544 545 545 r->compute.layer.image_array_size = 546 - MIN(vk->features.max_per_stage_descriptor_sampled_images, RENDER_MAX_IMAGES_COUNT(r)); 546 + MIN(vk->limits.max_per_stage_descriptor_sampled_images, RENDER_MAX_IMAGES_SIZE); 547 547 548 548 549 549 /*
+49
src/xrt/compositor/render/render_util.c
··· 87 87 * 88 88 */ 89 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 + 90 139 void 91 140 render_calc_time_warp_matrix(const struct xrt_pose *src_pose, 92 141 const struct xrt_fov *src_fov,
+38 -24
src/xrt/compositor/shaders/layer.comp
··· 1 1 // Copyright 2021-2023, Collabora Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // Author: Jakob Bornecrantz <jakob@collabora.com> 3 4 // Author: Christoph Haag <christoph.haag@collabora.com> 4 5 // SPDX-License-Identifier: BSL-1.0 ··· 7 8 #extension GL_GOOGLE_include_directive : require 8 9 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; 10 18 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 + // 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 + 19 34 20 35 const float PI = acos(-1); 21 36 ··· 40 55 vec4 pre_transform; 41 56 vec4 post_transform[RENDER_MAX_LAYERS]; 42 57 43 - // corresponds to enum xrt_layer_type 44 - uvec2 layer_type_and_unpremultiplied[RENDER_MAX_LAYERS]; 58 + // Per-layer data. 59 + layer_data layer_data[RENDER_MAX_LAYERS]; 45 60 46 61 // which image/sampler(s) correspond to each layer 47 - ivec2 images_samplers[RENDER_MAX_LAYERS]; 62 + image_info image_info[RENDER_MAX_LAYERS]; 48 63 49 64 // shared between cylinder and equirect2 50 65 mat4 mv_inverse[RENDER_MAX_LAYERS]; ··· 226 241 227 242 vec2 uv_sub = fma(sample_point, ubo.post_transform[layer].zw, ubo.post_transform[layer].xy); 228 243 229 - uint index = ubo.images_samplers[layer].x; 244 + uint index = ubo.image_info[layer].color_image_index; 230 245 #ifdef DEBUG 231 246 out_color += texture(source[index], uv_sub) / 2.f; 232 247 #else ··· 325 340 326 341 vec2 uv_sub = fma(sample_point, ubo.post_transform[layer].zw, ubo.post_transform[layer].xy); 327 342 328 - uint index = ubo.images_samplers[layer].x; 343 + uint index = ubo.image_info[layer].color_image_index; 329 344 #ifdef DEBUG 330 345 out_color += texture(source[index], uv_sub) / 2.0; 331 346 #else ··· 341 356 342 357 vec4 do_projection(vec2 view_uv, uint layer) 343 358 { 344 - uint source_image_index = ubo.images_samplers[layer].x; 359 + uint source_image_index = ubo.image_info[layer].color_image_index; 345 360 346 361 // Do any transformation needed. 347 362 vec2 uv = transform_uv(view_uv, layer); ··· 373 388 374 389 vec4 do_quad(vec2 view_uv, uint layer) 375 390 { 376 - uint source_image_index = ubo.images_samplers[layer].x; 391 + uint source_image_index = ubo.image_info[layer].color_image_index; 377 392 378 393 // center point of the plane in view space. 379 394 vec3 quad_position = ubo.quad_position[layer].xyz; ··· 459 474 for (uint layer = 0; layer < layer_count; layer++) { 460 475 vec4 rgba = vec4(0, 0, 0, 0); 461 476 462 - switch (ubo.layer_type_and_unpremultiplied[layer].x) { 463 - case XRT_LAYER_CYLINDER: 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: 464 482 rgba = do_cylinder(view_uv, layer); 465 483 break; 466 - case XRT_LAYER_EQUIRECT2: 484 + case LAYER_COMP_TYPE_EQUIRECT2: 467 485 rgba = do_equirect2(view_uv, layer); 468 486 break; 469 - case XRT_LAYER_PROJECTION: 470 - case XRT_LAYER_PROJECTION_DEPTH: 487 + case LAYER_COMP_TYPE_PROJECTION: 471 488 rgba = do_projection(view_uv, layer); 472 489 break; 473 - case XRT_LAYER_QUAD: 474 - rgba = do_quad(view_uv, layer); 475 - break; 476 490 default: break; 477 491 } 478 492 479 - if (ubo.layer_type_and_unpremultiplied[layer].y != 0) { 493 + if (ubo.layer_data[layer].unpremultiplied_alpha != 0) { 480 494 // Unpremultipled blend factor of src.a. 481 495 accum.rgb = mix(accum.rgb, rgba.rgb, rgba.a); 482 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 26 27 27 #include "render/render_interface.h" 28 28 29 + #include "shaders/layer_defines.inc.glsl" 30 + 29 31 #include "util/comp_render.h" 30 32 #include "util/comp_render_helpers.h" 31 33 #include "util/comp_base.h" ··· 33 35 34 36 /* 35 37 * 36 - * Compute layer data builders. 38 + * Helpers 37 39 * 38 40 */ 39 41 ··· 54 56 return &sc->images[image_index]; 55 57 } 56 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 + 57 80 /// Data setup for a cylinder layer 58 81 static inline void 59 82 do_cs_cylinder_layer(const struct comp_layer *layer, ··· 113 136 ubo_data->cylinder_data[cur_layer].central_angle = c->central_angle; 114 137 ubo_data->cylinder_data[cur_layer].aspect_ratio = c->aspect_ratio; 115 138 116 - ubo_data->images_samplers[cur_layer].images[0] = cur_image; 139 + ubo_data->image_info[cur_layer].color_image_index = cur_image; 117 140 cur_image++; 118 141 119 142 *out_cur_image = cur_image; ··· 176 199 ubo_data->eq2_data[cur_layer].upper_vertical_angle = eq2->upper_vertical_angle; 177 200 ubo_data->eq2_data[cur_layer].lower_vertical_angle = eq2->lower_vertical_angle; 178 201 179 - ubo_data->images_samplers[cur_layer].images[0] = cur_image; 202 + ubo_data->image_info[cur_layer].color_image_index = cur_image; 180 203 cur_image++; 181 204 182 205 *out_cur_image = cur_image; ··· 214 237 // Color 215 238 src_samplers[cur_image] = clamp_to_border_black; 216 239 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++; 240 + ubo_data->image_info[cur_layer + 0].color_image_index = cur_image++; 218 241 219 242 // Depth 220 243 if (layer_data->type == XRT_LAYER_PROJECTION_DEPTH) { ··· 224 247 225 248 src_samplers[cur_image] = clamp_to_edge; // Edge to keep depth stable at edges. 226 249 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++; 250 + ubo_data->image_info[cur_layer + 0].depth_image_index = cur_image++; 228 251 } 229 252 230 253 set_post_transform_rect( // ··· 323 346 ubo_data->quad_position[cur_layer].val = quad_position; 324 347 ubo_data->quad_normal[cur_layer].val = normal_view_space; 325 348 ubo_data->inverse_quad_transform[cur_layer] = inverse_quad_transform; 326 - ubo_data->images_samplers[cur_layer].images[0] = cur_image; 349 + ubo_data->image_info[cur_layer].color_image_index = cur_image; 327 350 cur_image++; 328 351 329 352 *out_cur_image = cur_image; ··· 660 683 continue; 661 684 } 662 685 663 - ubo_data->layer_type[cur_layer].val = data->type; 664 - ubo_data->layer_type[cur_layer].unpremultiplied = is_layer_unpremultiplied(data); 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); 665 688 666 689 // Finally okay to increment the current layer. 667 690 cur_layer++; ··· 671 694 ubo_data->layer_count.value = cur_layer; 672 695 673 696 for (uint32_t i = cur_layer; i < RENDER_MAX_LAYERS; i++) { 674 - ubo_data->layer_type[i].val = UINT32_MAX; 697 + ubo_data->layer_data[i].layer_type = LAYER_COMP_TYPE_NOOP; // Explicit no-op. 675 698 } 676 699 677 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 41 { 42 42 struct comp_swapchain *sc = comp_swapchain(xsc); 43 43 44 - VK_TRACE(sc->vk, "DESTROY"); 44 + VK_DEBUG(sc->vk, "%p DESTROY(not-actual)", (void *)sc); 45 45 46 46 u_threading_stack_push(&sc->cscs->destroy_swapchains, sc); 47 47 } ··· 476 476 static void 477 477 really_destroy(struct comp_swapchain *sc) 478 478 { 479 + VK_DEBUG(sc->vk, "%p REALLY_DESTROY", (void *)sc); 480 + 479 481 // Reuse close function. 480 482 comp_swapchain_teardown(sc); 481 483
+1 -6
src/xrt/drivers/android/android_sensors.c
··· 133 133 args->tray_to_lens_distance_meters = params.tray_to_lens_distance; 134 134 } 135 135 136 - #define DEG_TO_RAD(x) (float)(x * M_PI / 180.0) 137 136 args->fov = (struct xrt_fov){.angle_left = -DEG_TO_RAD(angles[0]), 138 137 .angle_right = DEG_TO_RAD(angles[1]), 139 138 .angle_down = -DEG_TO_RAD(angles[2]), 140 139 .angle_up = DEG_TO_RAD(angles[3])}; 141 - #undef DEG_TO_RAD 142 140 143 141 ANDROID_INFO(d, "loaded calibration for device %s (%s)", model, vendor); 144 142 ··· 354 352 struct android_device *d = U_DEVICE_ALLOCATE(struct android_device, flags, 1, 0); 355 353 356 354 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; 355 + u_device_populate_function_pointers(&d->base, android_device_get_tracked_pose, android_device_destroy); 361 356 d->base.get_view_poses = u_device_get_view_poses; 362 357 d->base.get_visibility_mask = u_device_get_visibility_mask; 363 358 d->base.compute_distortion = android_device_compute_distortion;
+2 -2
src/xrt/drivers/arduino/arduino_device.c
··· 405 405 406 406 m_imu_3dof_init(&ad->fusion, M_IMU_3DOF_USE_GRAVITY_DUR_300MS); 407 407 408 - #define DEG_TO_RAD ((double)M_PI / 180.0) 408 + #define DEG_TO_RAD_MULTIPLIER ((double)M_PI / 180.0) 409 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; 410 + float gyro_ticks_to_float = (2000.0 * DEG_TO_RAD_MULTIPLIER) / INT16_MAX; 411 411 412 412 m_imu_pre_filter_init(&ad->pre_filter, accel_ticks_to_float, gyro_ticks_to_float); 413 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 157 blubur_s1_hmd_get_view_poses(struct xrt_device *xdev, 158 158 const struct xrt_vec3 *default_eye_relation, 159 159 int64_t at_timestamp_ns, 160 + enum xrt_view_type view_type, 160 161 uint32_t view_count, 161 162 struct xrt_space_relation *out_head_relation, 162 163 struct xrt_fov *out_fovs, 163 164 struct xrt_pose *out_poses) 164 165 { 165 - return u_device_get_view_poses(xdev, default_eye_relation, at_timestamp_ns, view_count, out_head_relation, 166 - out_fovs, out_poses); 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); // 167 175 } 168 176 169 177 static void
+1 -5
src/xrt/drivers/euroc/euroc_device.c
··· 206 206 xd->inputs[0].name = XRT_INPUT_SIMPLE_GRIP_POSE; 207 207 } 208 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; 209 + u_device_populate_function_pointers(xd, euroc_device_get_tracked_pose, euroc_device_destroy); 212 210 if (is_hmd) { 213 211 xd->get_view_poses = u_device_get_view_poses; 214 - } else { 215 - xd->get_view_poses = u_device_ni_get_view_poses; 216 212 } 217 213 218 214 u_var_add_root(ed, dev_name, false);
+37 -19
src/xrt/drivers/ht_ctrl_emu/ht_ctrl_emu.cpp
··· 1 1 // Copyright 2021, Collabora, Ltd. 2 + // Copyright 2024-2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 45 46 enum cemu_input_index 46 47 { 47 48 CEMU_INDEX_HAND_TRACKING, 48 - CEMU_INDEX_SELECT, 49 - CEMU_INDEX_MENU, 49 + CEMU_INDEX_PINCH_BOOL, 50 + CEMU_INDEX_PINCH_FLOAT, 50 51 CEMU_INDEX_GRIP, 51 52 CEMU_INDEX_AIM, 52 53 CEMU_NUM_INPUTS, ··· 372 373 struct cemu_device *dev = cemu_device(xdev); 373 374 struct cemu_system *sys = dev->sys; 374 375 375 - if (name != XRT_INPUT_SIMPLE_GRIP_POSE && name != XRT_INPUT_SIMPLE_AIM_POSE) { 376 + if (name != XRT_INPUT_HAND_CTRL_EMU_AIM_POSE && name != XRT_INPUT_HAND_CTRL_EMU_GRIP_POSE) { 376 377 U_LOG_XDEV_UNSUPPORTED_INPUT(&dev->base, dev->sys->log_level, name); 377 378 return XRT_ERROR_INPUT_UNSUPPORTED; 378 379 } ··· 390 391 391 392 xret = XRT_SUCCESS; 392 393 switch (name) { 393 - case XRT_INPUT_SIMPLE_GRIP_POSE: { 394 + case XRT_INPUT_HAND_CTRL_EMU_GRIP_POSE: { 394 395 xret = do_grip_pose(&joint_set, out_relation, sys->grip_offset_from_palm, dev->hand_index); 395 396 break; 396 397 } 397 - case XRT_INPUT_SIMPLE_AIM_POSE: { 398 + case XRT_INPUT_HAND_CTRL_EMU_AIM_POSE: { 398 399 // Assume that now we're doing everything in the timestamp from the hand-tracker, so use 399 400 // hand_timestamp_ns. This will cause the controller to lag behind but otherwise be correct 400 401 xret = do_aim_pose(dev, &joint_set, at_timestamp_ns, hand_timestamp_ns, out_relation); ··· 435 436 U_LOG_CHK_AND_RET(sys->log_level, xret, "xrt_device_get_hand_tracking"); 436 437 437 438 if (!joint_set.is_active) { 438 - xdev->inputs[CEMU_INDEX_SELECT].value.boolean = false; 439 - xdev->inputs[CEMU_INDEX_MENU].value.boolean = false; 439 + xdev->inputs[CEMU_INDEX_PINCH_BOOL].value.boolean = false; 440 + xdev->inputs[CEMU_INDEX_PINCH_FLOAT].value.vec1.x = 0.f; 440 441 return XRT_SUCCESS; 441 442 } 442 443 443 444 decide(joint_set.values.hand_joint_set_default[XRT_HAND_JOINT_INDEX_TIP].relation.pose.position, 444 445 joint_set.values.hand_joint_set_default[XRT_HAND_JOINT_THUMB_TIP].relation.pose.position, 445 - &xdev->inputs[CEMU_INDEX_SELECT].value.boolean); 446 + &xdev->inputs[CEMU_INDEX_PINCH_BOOL].value.boolean); 446 447 447 448 // For now, all other inputs are off - detecting any gestures more complicated than pinch is too unreliable for 448 449 // now. 449 - xdev->inputs[CEMU_INDEX_MENU].value.boolean = false; 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 + } 450 455 451 456 return XRT_SUCCESS; 452 457 } 453 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 + }; 454 474 455 475 extern "C" int 456 476 cemu_devices_create(struct xrt_device *head, struct xrt_device *hands, struct xrt_device **out_xdevs) ··· 480 500 481 501 cemud[i]->base.tracking_origin = hands->tracking_origin; 482 502 483 - cemud[i]->base.name = XRT_DEVICE_SIMPLE_CONTROLLER; 503 + cemud[i]->base.name = XRT_DEVICE_HAND_CTRL_EMU; 484 504 cemud[i]->base.supported.hand_tracking = true; 485 505 cemud[i]->base.supported.orientation_tracking = true; 486 506 cemud[i]->base.supported.position_tracking = true; 487 - 507 + cemud[i]->base.binding_profiles = binding_profiles; 508 + cemud[i]->base.binding_profile_count = ARRAY_SIZE(binding_profiles); 488 509 489 510 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; 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; 494 515 516 + u_device_populate_function_pointers(&cemud[i]->base, cemu_device_get_tracked_pose, cemu_device_destroy); 495 517 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 518 cemud[i]->base.get_hand_tracking = cemu_device_get_hand_tracking; 499 - cemud[i]->base.destroy = cemu_device_destroy; 500 519 501 520 cemud[i]->base.device_type = 502 521 i ? XRT_DEVICE_TYPE_RIGHT_HAND_CONTROLLER : XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER; ··· 513 532 } 514 533 515 534 cemud[i]->ht_input_name = ht_input_names[i]; 516 - 517 535 cemud[i]->hand_index = i; 518 536 system->out_hand[i] = cemud[i]; 519 537
+2 -6
src/xrt/drivers/hydra/hydra_driver.c
··· 345 345 (XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT | XRT_SPACE_RELATION_ORIENTATION_VALID_BIT) | 346 346 (XRT_SPACE_RELATION_POSITION_TRACKED_BIT | XRT_SPACE_RELATION_POSITION_VALID_BIT); 347 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); 348 + m_relation_history_push_with_motion_estimation(state->relation_history, &space_relation, now); 351 349 352 350 state->buttons = hydra_read_uint8(&buf); 353 351 ··· 799 797 for (size_t i = 0; i < 2; ++i) { 800 798 struct hydra_device *hd = hs->devs[i]; 801 799 802 - hd->base.destroy = hydra_device_destroy; 800 + u_device_populate_function_pointers(&hd->base, hydra_device_get_tracked_pose, hydra_device_destroy); 803 801 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 802 hd->base.name = XRT_DEVICE_HYDRA; 807 803 snprintf(hd->base.str, XRT_DEVICE_NAME_LEN, "%s %i", "Razer Hydra Controller", (int)(i + 1)); 808 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 196 get_view_poses(struct xrt_device *xdev, 197 197 const struct xrt_vec3 *default_eye_relation, 198 198 int64_t at_timestamp_ns, 199 + enum xrt_view_type view_type, 199 200 uint32_t view_count, 200 201 struct xrt_space_relation *out_head_relation, 201 202 struct xrt_fov *out_fovs, ··· 203 204 { 204 205 struct multi_device *d = (struct multi_device *)xdev; 205 206 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); 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); // 208 217 if (xret != XRT_SUCCESS) { 209 218 return xret; 210 219 }
+2
src/xrt/drivers/north_star/ns_hmd.c
··· 389 389 ns_hmd_get_view_poses(struct xrt_device *xdev, 390 390 const struct xrt_vec3 *default_eye_relation, 391 391 int64_t at_timestamp_ns, 392 + enum xrt_view_type view_type, 392 393 uint32_t view_count, 393 394 struct xrt_space_relation *out_head_relation, 394 395 struct xrt_fov *out_fovs, ··· 402 403 xdev, // 403 404 default_eye_relation, // 404 405 at_timestamp_ns, // 406 + view_type, // 405 407 view_count, // 406 408 out_head_relation, // 407 409 out_fovs, //
+2 -5
src/xrt/drivers/ohmd/oh_device.c
··· 757 757 758 758 enum u_device_alloc_flags flags = U_DEVICE_ALLOC_HMD; 759 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); 760 761 ohd->base.update_inputs = oh_device_update_inputs; 761 - ohd->base.get_tracked_pose = oh_device_get_tracked_pose; 762 762 ohd->base.get_view_poses = u_device_get_view_poses; 763 - ohd->base.destroy = oh_device_destroy; 764 763 ohd->base.inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE; 765 764 ohd->base.name = XRT_DEVICE_GENERIC_HMD; 766 765 ohd->ctx = ctx; ··· 1074 1073 1075 1074 enum u_device_alloc_flags flags = 0; 1076 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 1077 ohd->base.update_inputs = oh_device_update_inputs; 1078 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 1079 if (oculus_touch) { 1083 1080 ohd->ohmd_device_type = OPENHMD_OCULUS_RIFT_CONTROLLER; 1084 1081 ohd->base.name = XRT_DEVICE_TOUCH_CONTROLLER;
+6 -8
src/xrt/drivers/pssense/pssense_driver.c
··· 43 43 44 44 DEBUG_GET_ONCE_LOG_OPTION(pssense_log, "PSSENSE_LOG", U_LOGGING_INFO) 45 45 46 - #define DEG_TO_RAD(DEG) (DEG * M_PI / 180.) 47 - 48 46 static struct xrt_binding_input_pair simple_inputs_pssense[4] = { 49 47 {XRT_INPUT_SIMPLE_SELECT_CLICK, XRT_INPUT_PSSENSE_TRIGGER_VALUE}, 50 48 {XRT_INPUT_SIMPLE_MENU_CLICK, XRT_INPUT_PSSENSE_OPTIONS_CLICK}, ··· 84 82 PSSENSE_INDEX_CIRCLE_TOUCH, 85 83 PSSENSE_INDEX_SQUEEZE_CLICK, 86 84 PSSENSE_INDEX_SQUEEZE_TOUCH, 87 - PSSENSE_INDEX_SQUEEZE_PROXIMITY, 85 + PSSENSE_INDEX_SQUEEZE_PROXIMITY_FLOAT, 88 86 PSSENSE_INDEX_TRIGGER_CLICK, 89 87 PSSENSE_INDEX_TRIGGER_TOUCH, 90 88 PSSENSE_INDEX_TRIGGER_VALUE, 91 - PSSENSE_INDEX_TRIGGER_PROXIMITY, 89 + PSSENSE_INDEX_TRIGGER_PROXIMITY_FLOAT, 92 90 PSSENSE_INDEX_THUMBSTICK, 93 91 PSSENSE_INDEX_THUMBSTICK_CLICK, 94 92 PSSENSE_INDEX_THUMBSTICK_TOUCH, ··· 661 659 pssense->base.inputs[PSSENSE_INDEX_CIRCLE_TOUCH].value.boolean = pssense->state.circle_touch; 662 660 pssense->base.inputs[PSSENSE_INDEX_SQUEEZE_CLICK].value.boolean = pssense->state.squeeze_click; 663 661 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; 662 + pssense->base.inputs[PSSENSE_INDEX_SQUEEZE_PROXIMITY_FLOAT].value.vec1.x = pssense->state.squeeze_proximity; 665 663 pssense->base.inputs[PSSENSE_INDEX_TRIGGER_CLICK].value.boolean = pssense->state.trigger_click; 666 664 pssense->base.inputs[PSSENSE_INDEX_TRIGGER_TOUCH].value.boolean = pssense->state.trigger_touch; 667 665 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; 666 + pssense->base.inputs[PSSENSE_INDEX_TRIGGER_PROXIMITY_FLOAT].value.vec1.x = pssense->state.trigger_proximity; 669 667 pssense->base.inputs[PSSENSE_INDEX_THUMBSTICK].value.vec2 = pssense->state.thumbstick; 670 668 pssense->base.inputs[PSSENSE_INDEX_THUMBSTICK_CLICK].value.boolean = pssense->state.thumbstick_click; 671 669 pssense->base.inputs[PSSENSE_INDEX_THUMBSTICK_TOUCH].value.boolean = pssense->state.thumbstick_touch; ··· 933 931 SET_INPUT(CIRCLE_TOUCH); 934 932 SET_INPUT(SQUEEZE_CLICK); 935 933 SET_INPUT(SQUEEZE_TOUCH); 936 - SET_INPUT(SQUEEZE_PROXIMITY); 934 + SET_INPUT(SQUEEZE_PROXIMITY_FLOAT); 937 935 SET_INPUT(TRIGGER_CLICK); 938 936 SET_INPUT(TRIGGER_TOUCH); 939 937 SET_INPUT(TRIGGER_VALUE); 940 - SET_INPUT(TRIGGER_PROXIMITY); 938 + SET_INPUT(TRIGGER_PROXIMITY_FLOAT); 941 939 SET_INPUT(THUMBSTICK); 942 940 SET_INPUT(THUMBSTICK_CLICK); 943 941 SET_INPUT(THUMBSTICK_TOUCH);
+1 -4
src/xrt/drivers/realsense/rs_ddev.c
··· 448 448 449 449 U_LOG_D("Realsense opts are %i %i %i %i %i\n", rs->enable_mapping, rs->enable_pose_jumping, 450 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; 451 + u_device_populate_function_pointers(&rs->base, rs_ddev_get_tracked_pose, rs_ddev_destroy); 455 452 rs->base.name = XRT_DEVICE_REALSENSE; 456 453 rs->base.tracking_origin->type = XRT_TRACKING_TYPE_EXTERNAL_SLAM; 457 454
+1 -4
src/xrt/drivers/remote/r_device.c
··· 193 193 struct r_device, flags, input_count, output_count); 194 194 195 195 // Setup the basics. 196 + u_device_populate_function_pointers(&rd->base, r_device_get_tracked_pose, r_device_destroy); 196 197 rd->base.update_inputs = r_device_update_inputs; 197 - rd->base.get_tracked_pose = r_device_get_tracked_pose; 198 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 199 rd->base.tracking_origin = &r->origin; 203 200 rd->base.supported.orientation_tracking = true; 204 201 rd->base.supported.position_tracking = true;
+3 -5
src/xrt/drivers/remote/r_hmd.c
··· 78 78 r_hmd_get_view_poses(struct xrt_device *xdev, 79 79 const struct xrt_vec3 *default_eye_relation, 80 80 int64_t at_timestamp_ns, 81 + enum xrt_view_type view_type, 81 82 uint32_t view_count, 82 83 struct xrt_space_relation *out_head_relation, 83 84 struct xrt_fov *out_fovs, ··· 90 91 xdev, // 91 92 default_eye_relation, // 92 93 at_timestamp_ns, // 94 + view_type, // 93 95 view_count, // 94 96 out_head_relation, // 95 97 out_fovs, // ··· 122 124 struct r_hmd, flags, input_count, output_count); 123 125 124 126 // 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; 127 + u_device_populate_function_pointers(&rh->base, r_hmd_get_tracked_pose, r_hmd_destroy); 128 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 129 rh->base.tracking_origin = &r->origin; 132 130 rh->base.supported.orientation_tracking = true; 133 131 rh->base.supported.position_tracking = true;
+10 -7
src/xrt/drivers/rift/rift_hmd.c
··· 230 230 rift_hmd_get_view_poses(struct xrt_device *xdev, 231 231 const struct xrt_vec3 *default_eye_relation, 232 232 int64_t at_timestamp_ns, 233 + enum xrt_view_type view_type, 233 234 uint32_t view_count, 234 235 struct xrt_space_relation *out_head_relation, 235 236 struct xrt_fov *out_fovs, ··· 237 238 { 238 239 struct rift_hmd *hmd = rift_hmd(xdev); 239 240 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); 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); 247 250 } 248 251 249 252 static xrt_result_t
-1
src/xrt/drivers/rift/rift_interface.h
··· 37 37 #define IMU_SAMPLE_RATE (1000) // 1000hz 38 38 #define NS_PER_SAMPLE (1000 * 1000) // 1ms (1,000,000 ns) per sample 39 39 40 - #define DEG_TO_RAD(DEG) (DEG * M_PI / 180.0) 41 40 #define MICROMETERS_TO_METERS(microns) (float)microns / 1000000.0f 42 41 43 42 // value taken from LibOVR 0.4.4
+1 -5
src/xrt/drivers/rift_s/rift_s_controller.c
··· 40 40 /* Set to 1 to print controller states continuously */ 41 41 #define DUMP_CONTROLLER_STATE 0 42 42 43 - #define DEG_TO_RAD(D) ((D)*M_PI / 180.) 44 - 45 43 static struct xrt_binding_input_pair simple_inputs_rift_s[4] = { 46 44 {XRT_INPUT_SIMPLE_SELECT_CLICK, XRT_INPUT_TOUCH_TRIGGER_VALUE}, 47 45 {XRT_INPUT_SIMPLE_MENU_CLICK, XRT_INPUT_TOUCH_MENU_CLICK}, ··· 606 604 607 605 os_mutex_init(&ctrl->mutex); 608 606 607 + u_device_populate_function_pointers(&ctrl->base, rift_s_controller_get_tracked_pose, rift_s_controller_destroy); 609 608 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 609 ctrl->base.get_view_poses = u_device_get_view_poses; 613 - ctrl->base.destroy = rift_s_controller_destroy; 614 610 ctrl->base.name = XRT_DEVICE_TOUCH_CONTROLLER; 615 611 ctrl->base.device_type = device_type; 616 612
-2
src/xrt/drivers/rift_s/rift_s_hmd.c
··· 40 40 41 41 #include "rift_s_hmd.h" 42 42 43 - #define DEG_TO_RAD(D) ((D)*M_PI / 180.) 44 - 45 43 46 44 static xrt_result_t 47 45 rift_s_get_tracked_pose(struct xrt_device *xdev,
+2
src/xrt/drivers/sample/sample_hmd.c
··· 132 132 sample_hmd_get_view_poses(struct xrt_device *xdev, 133 133 const struct xrt_vec3 *default_eye_relation, 134 134 int64_t at_timestamp_ns, 135 + enum xrt_view_type view_type, 135 136 uint32_t view_count, 136 137 struct xrt_space_relation *out_head_relation, 137 138 struct xrt_fov *out_fovs, ··· 145 146 xdev, // 146 147 default_eye_relation, // 147 148 at_timestamp_ns, // 149 + view_type, // 148 150 view_count, // 149 151 out_head_relation, // 150 152 out_fovs, //
+2 -2
src/xrt/drivers/simula/svr_hmd.c
··· 97 97 return XRT_SUCCESS; 98 98 } 99 99 100 - #define DEG_TO_RAD(DEG) (DEG * M_PI / 180.) 101 - 102 100 static xrt_result_t 103 101 svr_hmd_get_view_poses(struct xrt_device *xdev, 104 102 const struct xrt_vec3 *default_eye_relation, 105 103 int64_t at_timestamp_ns, 104 + enum xrt_view_type view_type, 106 105 uint32_t view_count, 107 106 struct xrt_space_relation *out_head_relation, 108 107 struct xrt_fov *out_fovs, ··· 115 114 xdev, // 116 115 default_eye_relation, // 117 116 at_timestamp_ns, // 117 + view_type, // 118 118 view_count, // 119 119 out_head_relation, // 120 120 out_fovs, //
+1 -5
src/xrt/drivers/simulated/simulated_controller.c
··· 347 347 348 348 // Allocate. 349 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); 350 351 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 352 sd->base.tracking_origin = origin; 357 353 sd->base.supported.orientation_tracking = true; 358 354 sd->base.supported.position_tracking = true;
+365 -101
src/xrt/drivers/steamvr_lh/device.cpp
··· 9 9 */ 10 10 11 11 #include "math/m_api.h" 12 + #include "math/m_predict.h" 12 13 #include "math/m_relation_history.h" 13 14 #include "math/m_space.h" 14 15 ··· 16 17 17 18 #include "util/u_debug.h" 18 19 #include "util/u_device.h" 19 - #include "util/u_hand_simulation.h" 20 20 #include "util/u_hand_tracking.h" 21 21 #include "util/u_logging.h" 22 22 #include "util/u_json.hpp" 23 23 24 + #include "util/u_time.h" 24 25 #include "xrt/xrt_defines.h" 25 26 #include "xrt/xrt_device.h" 26 27 #include "xrt/xrt_prober.h" ··· 34 35 #include <cmath> 35 36 #include <functional> 36 37 #include <cstring> 38 + #include <numbers> 39 + #include <openvr_driver.h> 37 40 #include <thread> 38 41 #include <algorithm> 39 42 #include <map> 40 - 41 43 42 44 #define DEV_ERR(...) U_LOG_IFL_E(ctx->log_level, __VA_ARGS__) 43 45 #define DEV_WARN(...) U_LOG_IFL_W(ctx->log_level, __VA_ARGS__) ··· 52 54 xrt_device_name name; 53 55 const std::vector<xrt_input_name> poses; 54 56 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 }; 57 58 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 + 59 98 // Adding support for a new controller is a simple as adding it here. 60 99 // The key for the map needs to be the name of input profile as indicated by the lighthouse driver. 61 100 const std::unordered_map<std::string_view, InputClass> controller_classes{ ··· 66 105 { 67 106 XRT_INPUT_VIVE_GRIP_POSE, 68 107 XRT_INPUT_VIVE_AIM_POSE, 108 + XRT_INPUT_GENERIC_PALM_POSE, 69 109 }, 70 110 { 71 111 {"/input/application_menu/click", XRT_INPUT_VIVE_MENU_CLICK}, ··· 76 116 {"/input/trigger/value", XRT_INPUT_VIVE_TRIGGER_VALUE}, 77 117 {"/input/grip/click", XRT_INPUT_VIVE_SQUEEZE_CLICK}, 78 118 {"/input/trackpad", XRT_INPUT_VIVE_TRACKPAD}, 79 - }, 80 - { 81 - // No fingers on this controller type 82 119 }, 83 120 }, 84 121 }, ··· 89 126 { 90 127 XRT_INPUT_INDEX_GRIP_POSE, 91 128 XRT_INPUT_INDEX_AIM_POSE, 129 + XRT_INPUT_GENERIC_PALM_POSE, 92 130 }, 93 131 { 94 132 {"/input/system/click", XRT_INPUT_INDEX_SYSTEM_CLICK}, ··· 109 147 {"/input/trackpad/touch", XRT_INPUT_INDEX_TRACKPAD_TOUCH}, 110 148 {"/input/trackpad", XRT_INPUT_INDEX_TRACKPAD}, 111 149 }, 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 150 }, 119 151 }, 120 152 { ··· 130 162 {"/input/application_menu/click", XRT_INPUT_VIVE_TRACKER_MENU_CLICK}, 131 163 {"/input/trigger/click", XRT_INPUT_VIVE_TRACKER_TRIGGER_CLICK}, 132 164 {"/input/thumb/click", XRT_INPUT_VIVE_TRACKER_TRACKPAD_CLICK}, 133 - }, 134 - { 135 - // No fingers on this controller type 136 165 }, 137 166 }, 138 167 }, ··· 150 179 {"/input/trigger/click", XRT_INPUT_VIVE_TRACKER_TRIGGER_CLICK}, 151 180 {"/input/thumb/click", XRT_INPUT_VIVE_TRACKER_TRACKPAD_CLICK}, 152 181 }, 153 - { 154 - // No fingers on this controller type 155 - }, 156 182 }, 157 183 }, 158 184 }; 159 - 160 185 int64_t 161 186 chrono_timestamp_ns() 162 187 { ··· 214 239 215 240 return brightness; 216 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 + } 217 248 } // namespace 218 249 219 250 Property::Property(vr::PropertyTypeTag_t tag, void *buffer, uint32_t bufferSize) ··· 249 280 this->xrt_device::get_hand_tracking = 250 281 &device_bouncer<ControllerDevice, &ControllerDevice::get_hand_tracking, xrt_result_t>; 251 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]; 252 286 } 253 287 254 288 Device::~Device() ··· 285 319 init_chaperone(builder.steam_install); 286 320 } 287 321 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 322 // NOTE: No operations that would force inputs_vec or finger_inputs_vec to reallocate (such as insertion) 297 323 // should be done after this function is called, otherwise the pointers in inputs_map/finger_inputs_map 298 324 // would be invalidated. ··· 314 340 inputs_map.insert({path, &inputs_vec.back()}); 315 341 } 316 342 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 343 this->inputs = inputs_vec.data(); 331 344 this->input_count = inputs_vec.size(); 332 345 } ··· 345 358 } 346 359 } 347 360 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 - }; 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 351 439 352 440 void 353 - ControllerDevice::update_hand_tracking(int64_t desired_timestamp_ns, struct xrt_hand_joint_set *out) 441 + ControllerDevice::set_skeleton(std::span<const vr::VRBoneTransform_t> bones, 442 + xrt_hand hand, 443 + bool is_simulated, 444 + const char *path) 354 445 { 355 - if (!has_index_hand_tracking) 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; 356 469 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 470 } 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 - } 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; 377 497 } 378 - auto curl_values = u_hand_tracking_curl_values{pinky, ring, middle, index, thumb}; 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 + } 379 551 380 - struct xrt_space_relation hand_relation = {}; 381 - m_relation_history_get(relation_hist, desired_timestamp_ns, &hand_relation); 552 + joints[XRT_HAND_JOINT_WRIST].relation.pose = wrist_xr; 553 + joints[XRT_HAND_JOINT_WRIST].relation.relation_flags = valid_flags; 382 554 383 - u_hand_sim_simulate_for_valve_index_knuckles(&curl_values, get_xrt_hand(), &hand_relation, out); 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; 384 560 385 - struct xrt_relation_chain chain = {}; 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 + } 386 568 387 - struct xrt_pose pose_offset = XRT_POSE_IDENTITY; 388 - vive_poses_get_pose_offset(name, device_type, inputs_map["HAND"]->name, &pose_offset); 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); 389 583 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); 584 + u_hand_joints_apply_joint_width(&joint_set); 585 + this->joint_history.push_back(JointsWithTimestamp{joint_set, timestamp}); 393 586 } 394 587 395 588 xrt_input * 396 589 Device::get_input_from_name(const std::string_view name) 397 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 + 398 595 // 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") { 596 + if (std::ranges::find(ignore_inputs, name) != std::ranges::end(ignore_inputs)) { 401 597 return nullptr; 402 598 } 403 599 auto input = inputs_map.find(name); ··· 447 643 return XRT_SUCCESS; 448 644 } 449 645 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 646 xrt_result_t 462 647 ControllerDevice::get_hand_tracking(enum xrt_input_name name, 463 648 int64_t desired_timestamp_ns, 464 649 struct xrt_hand_joint_set *out_value, 465 650 int64_t *out_timestamp_ns) 466 651 { 467 - if (!has_index_hand_tracking) 652 + if (!has_hand_tracking) { 468 653 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; 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 + 473 718 return XRT_SUCCESS; 474 719 } 475 720 ··· 527 772 Device::get_pose(at_timestamp_ns, &rel); 528 773 529 774 xrt_pose pose_offset = XRT_POSE_IDENTITY; 530 - vive_poses_get_pose_offset(input_class->name, device_type, name, &pose_offset); 531 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 + } 532 787 xrt_relation_chain relchain = {}; 533 788 534 789 m_relation_chain_push_pose(&relchain, &pose_offset); ··· 605 860 xrt_result_t 606 861 HmdDevice::get_view_poses(const xrt_vec3 *default_eye_relation, 607 862 uint64_t at_timestamp_ns, 863 + xrt_view_type view_type, 608 864 uint32_t view_count, 609 865 xrt_space_relation *out_head_relation, 610 866 xrt_fov *out_fovs, ··· 617 873 this, // 618 874 &eye_relation, // 619 875 at_timestamp_ns, // 876 + view_type, // 620 877 view_count, // 621 878 out_head_relation, // 622 879 out_fovs, // ··· 804 1061 relation.linear_velocity = copy_vec3(newPose.vecVelocity); 805 1062 relation.angular_velocity = copy_vec3(newPose.vecAngularVelocity); 806 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 807 1074 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 1075 math_pose_transform(&relation.pose, &local, &relation.pose); 812 1076 813 1077 // apply world transform ··· 868 1132 } 869 1133 870 1134 void 871 - HmdDevice::set_scanout_type(xrt_scanout_direction direction, uint64_t time_ns) 1135 + HmdDevice::set_scanout_type(xrt_scanout_direction direction, int64_t time_ns) 872 1136 { 873 1137 auto set = [this, direction, time_ns] { 874 1138 hmd_parts->base.screens[0].scanout_direction = direction; ··· 1047 1311 case vr::Prop_DisplayFrequency_Float: { 1048 1312 assert(prop.unBufferSize == sizeof(float)); 1049 1313 float freq = *static_cast<float *>(prop.pvBuffer); 1050 - uint64_t interval_ns = (1.f / freq) * 1e9f; 1314 + int64_t interval_ns = (1.f / freq) * 1e9f; 1051 1315 set_nominal_frame_interval(interval_ns); 1052 1316 if (variant == VIVE_VARIANT_PRO) { 1053 1317 set_scanout_type(XRT_SCANOUT_DIRECTION_TOP_TO_BOTTOM, interval_ns * 1600.0 / 1624.0); ··· 1129 1393 const std::string_view name = {static_cast<char *>(prop.pvBuffer), prop.unBufferSize}; 1130 1394 if (name == "SlimeVR Virtual Tracker\0"sv) { 1131 1395 static const InputClass input_class = { 1132 - XRT_DEVICE_VIVE_TRACKER, {XRT_INPUT_GENERIC_TRACKER_POSE}, {}, {}}; 1396 + XRT_DEVICE_VIVE_TRACKER, {XRT_INPUT_GENERIC_TRACKER_POSE}, {}}; 1133 1397 this->name = input_class.name; 1134 1398 set_input_class(&input_class); 1135 1399 this->manufacturer = name.substr(0, name.find_first_of(' ')); ··· 1148 1412 } 1149 1413 case vr::TrackedControllerRole_RightHand: { 1150 1414 this->device_type = XRT_DEVICE_TYPE_RIGHT_HAND_CONTROLLER; 1151 - set_hand_tracking_hand(XRT_INPUT_HT_CONFORMING_RIGHT); 1415 + set_active_hand(XRT_HAND_RIGHT); 1152 1416 break; 1153 1417 } 1154 1418 case vr::TrackedControllerRole_LeftHand: { 1155 1419 this->device_type = XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER; 1156 - set_hand_tracking_hand(XRT_INPUT_HT_CONFORMING_LEFT); 1420 + set_active_hand(XRT_HAND_LEFT); 1157 1421 break; 1158 1422 } 1159 1423 case vr::TrackedControllerRole_OptOut: {
+26 -11
src/xrt/drivers/steamvr_lh/device.hpp
··· 11 11 12 12 #include "math/m_relation_history.h" 13 13 14 + #include "util/u_template_historybuf.hpp" 14 15 #include "xrt/xrt_device.h" 15 16 16 17 #include "vive/vive_common.h" ··· 23 24 #include <vector> 24 25 #include <memory> 25 26 #include <unordered_map> 27 + #include <span> 28 + #include <array> 29 + #include <optional> 26 30 27 31 #include <condition_variable> 28 32 #include <mutex> ··· 176 180 xrt_result_t 177 181 get_view_poses(const xrt_vec3 *default_eye_relation, 178 182 uint64_t at_timestamp_ns, 183 + xrt_view_type view_type, 179 184 uint32_t view_count, 180 185 xrt_space_relation *out_head_relation, 181 186 xrt_fov *out_fovs, ··· 211 216 set_nominal_frame_interval(uint64_t interval_ns); 212 217 213 218 void 214 - set_scanout_type(enum xrt_scanout_direction direction, uint64_t time_ns); 219 + set_scanout_type(enum xrt_scanout_direction direction, int64_t time_ns); 215 220 216 221 std::condition_variable hmd_parts_cv; 217 222 std::mutex hmd_parts_mut; ··· 233 238 xrt_result_t 234 239 get_tracked_pose(xrt_input_name name, uint64_t at_timestamp_ns, xrt_space_relation *out_relation) override; 235 240 236 - IndexFingerInput * 237 - get_finger_from_name(std::string_view name); 238 - 239 241 xrt_result_t 240 242 get_hand_tracking(enum xrt_input_name name, 241 243 int64_t desired_timestamp_ns, ··· 246 248 get_xrt_hand(); 247 249 248 250 void 249 - update_hand_tracking(int64_t desired_timestamp_ns, struct xrt_hand_joint_set *out); 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); 250 258 251 259 protected: 252 260 void 253 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); 254 265 255 266 private: 256 267 vr::VRInputComponentHandle_t haptic_handle{0}; 257 268 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; 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{}; 262 273 263 - void 264 - set_hand_tracking_hand(xrt_input_name name); 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; 265 280 266 281 vr::ETrackedPropertyError 267 282 handle_property_write(const vr::PropertyWrite_t &prop) override;
+2 -17
src/xrt/drivers/steamvr_lh/interfaces/context.hpp
··· 28 28 29 29 #include "xrt/xrt_tracking.h" 30 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 31 struct xrt_input; 48 32 class Device; 33 + class ControllerDevice; 49 34 class Context final : public xrt_tracking_origin, 50 35 public vr::IVRDriverContext, 51 36 public vr::IVRServerDriverHost, ··· 70 55 71 56 std::vector<vr::VRInputComponentHandle_t> handles; 72 57 std::unordered_map<vr::VRInputComponentHandle_t, xrt_input *> handle_to_input; 73 - std::unordered_map<vr::VRInputComponentHandle_t, IndexFingerInput *> handle_to_finger; 74 58 struct Vec2Components 75 59 { 76 60 vr::VRInputComponentHandle_t x; ··· 78 62 }; 79 63 std::unordered_map<vr::VRInputComponentHandle_t, Vec2Components *> vec2_inputs; 80 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; 81 66 82 67 struct Event 83 68 {
+57 -24
src/xrt/drivers/steamvr_lh/steamvr_lh.cpp
··· 162 162 MATCH_INTERFACE(vr::IVRDriverManager_Version, &man); 163 163 MATCH_INTERFACE(vr::IVRBlockQueue_Version, &blockqueue); 164 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); 165 168 166 169 // Internal interfaces 167 170 MATCH_INTERFACE("IVRServer_XXX", &server); ··· 479 482 return vr::VRInputError_InvalidHandle; 480 483 } 481 484 if (xrt_input *input = device->get_input_from_name(name); input) { 482 - CTX_DEBUG("creating component %s", name); 485 + CTX_DEBUG("creating component %s for %p", name, (void *)device); 483 486 vr::VRInputComponentHandle_t handle = new_handle(); 484 487 handle_to_input[handle] = input; 485 488 *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 489 } 495 490 return vr::VRInputError_None; 496 491 } ··· 593 588 } else { 594 589 input->value.vec1.x = fNewValue; 595 590 } 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 591 } 612 592 return vr::VRInputError_None; 613 593 } ··· 649 629 uint32_t unGripLimitTransformCount, 650 630 vr::VRInputComponentHandle_t *pHandle) 651 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 + 652 659 return vr::VRInputError_None; 653 660 } 654 661 ··· 658 665 const vr::VRBoneTransform_t *pTransforms, 659 666 uint32_t unTransformCount) 660 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 + 661 684 return vr::VRInputError_None; 662 685 } 663 686 ··· 754 777 out_roles->left = left; 755 778 out_roles->right = right; 756 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 + } 757 790 } 758 791 759 792 return XRT_SUCCESS;
+2
src/xrt/drivers/survive/survive_driver.c
··· 530 530 survive_device_get_view_poses(struct xrt_device *xdev, 531 531 const struct xrt_vec3 *default_eye_relation, 532 532 int64_t at_timestamp_ns, 533 + enum xrt_view_type view_type, 533 534 uint32_t view_count, 534 535 struct xrt_space_relation *out_head_relation, 535 536 struct xrt_fov *out_fovs, ··· 554 555 xdev, // 555 556 &eye_relation, // 556 557 at_timestamp_ns, // 558 + view_type, // 557 559 view_count, // 558 560 out_head_relation, // 559 561 out_fovs, //
+1 -4
src/xrt/drivers/twrap/twrap_slam.c
··· 159 159 160 160 161 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; 162 + u_device_populate_function_pointers(&dx->base, twrap_slam_get_tracked_pose, twrap_slam_destroy); 166 163 dx->base.name = name; 167 164 dx->base.tracking_origin->type = XRT_TRACKING_TYPE_OTHER; 168 165 dx->base.inputs[0].name = XRT_INPUT_GENERIC_TRACKER_POSE;
+2
src/xrt/drivers/vive/vive_device.c
··· 212 212 vive_device_get_view_poses(struct xrt_device *xdev, 213 213 const struct xrt_vec3 *default_eye_relation, 214 214 int64_t at_timestamp_ns, 215 + enum xrt_view_type view_type, 215 216 uint32_t view_count, 216 217 struct xrt_space_relation *out_head_relation, 217 218 struct xrt_fov *out_fovs, ··· 226 227 xdev, // 227 228 default_eye_relation, // 228 229 at_timestamp_ns, // 230 + view_type, // 229 231 view_count, // 230 232 out_head_relation, // 231 233 out_fovs, //
+1 -1
src/xrt/drivers/vp2/vp2_hid.c
··· 256 256 VP2_INFO(vp2, "Destroyed Vive Pro 2 HID device."); 257 257 258 258 free(vp2); 259 - } 259 + }
+4 -2
src/xrt/drivers/wmr/wmr_controller_base.c
··· 526 526 wmr_controller_base_init(struct wmr_controller_base *wcb, 527 527 struct wmr_controller_connection *conn, 528 528 enum xrt_device_type controller_type, 529 - enum u_logging_level log_level) 529 + enum u_logging_level log_level, 530 + u_device_destroy_function_t destroy_fn) 530 531 { 531 532 DRV_TRACE_MARKER(); 532 533 ··· 544 545 snprintf(wcb->base.serial, XRT_DEVICE_NAME_LEN, "Right Controller"); 545 546 } 546 547 547 - wcb->base.get_tracked_pose = wmr_controller_base_get_tracked_pose; 548 + // Set all functions. 549 + u_device_populate_function_pointers(&wcb->base, wmr_controller_base_get_tracked_pose, destroy_fn); 548 550 549 551 wcb->base.name = XRT_DEVICE_WMR_CONTROLLER; 550 552 wcb->base.device_type = controller_type;
+3 -1
src/xrt/drivers/wmr/wmr_controller_base.h
··· 16 16 17 17 #include "os/os_threading.h" 18 18 #include "math/m_imu_3dof.h" 19 + #include "util/u_device.h" 19 20 #include "util/u_logging.h" 20 21 #include "xrt/xrt_device.h" 21 22 ··· 129 130 wmr_controller_base_init(struct wmr_controller_base *wcb, 130 131 struct wmr_controller_connection *conn, 131 132 enum xrt_device_type controller_type, 132 - enum u_logging_level log_level); 133 + enum u_logging_level log_level, 134 + u_device_destroy_function_t destroy_fn); 133 135 134 136 void 135 137 wmr_controller_base_deinit(struct wmr_controller_base *wcb);
+3 -5
src/xrt/drivers/wmr/wmr_controller_hp.c
··· 360 360 U_DEVICE_ALLOCATE(struct wmr_controller_hp, flags, WMR_CONTROLLER_INDEX_COUNT, 1); 361 361 struct wmr_controller_base *wcb = (struct wmr_controller_base *)(ctrl); 362 362 363 - if (!wmr_controller_base_init(wcb, conn, controller_type, log_level)) { 363 + if (!wmr_controller_base_init(wcb, conn, controller_type, log_level, wmr_controller_hp_destroy)) { 364 364 wmr_controller_hp_destroy(&wcb->base); 365 365 return NULL; 366 366 } 367 367 368 368 wcb->handle_input_packet = handle_input_packet; 369 369 370 + // Only set those we want to overwrite. 371 + wcb->base.update_inputs = wmr_controller_hp_update_inputs; 370 372 wcb->base.name = XRT_DEVICE_HP_REVERB_G2_CONTROLLER; 371 373 372 374 if (controller_type == XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER) { ··· 374 376 } else { 375 377 snprintf(wcb->base.str, ARRAY_SIZE(wcb->base.str), "HP Reverb G2 Right Controller"); 376 378 } 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 379 382 380 SET_INPUT(wcb, MENU_CLICK, MENU_CLICK); 383 381 SET_INPUT(wcb, HOME_CLICK, HOME_CLICK);
+4 -4
src/xrt/drivers/wmr/wmr_controller_og.c
··· 413 413 struct wmr_controller_og *ctrl = U_DEVICE_ALLOCATE(struct wmr_controller_og, flags, 11, 1); 414 414 struct wmr_controller_base *wcb = (struct wmr_controller_base *)(ctrl); 415 415 416 - if (!wmr_controller_base_init(wcb, conn, controller_type, log_level)) { 416 + if (!wmr_controller_base_init(wcb, conn, controller_type, log_level, wmr_controller_og_destroy)) { 417 417 wmr_controller_og_destroy(&wcb->base); 418 418 return NULL; 419 419 } 420 420 421 421 wcb->handle_input_packet = handle_input_packet; 422 422 423 + // Only set those we want to overwrite. 424 + wcb->base.update_inputs = wmr_controller_og_update_inputs; 425 + 423 426 if (pid == ODYSSEY_CONTROLLER_PID) { 424 427 wcb->base.name = XRT_DEVICE_SAMSUNG_ODYSSEY_CONTROLLER; 425 428 } else { 426 429 wcb->base.name = XRT_DEVICE_WMR_CONTROLLER; 427 430 } 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 431 432 432 if (pid == ODYSSEY_CONTROLLER_PID) { 433 433 SET_ODYSSEY_INPUT(wcb, MENU_CLICK);
+12
src/xrt/drivers/wmr/wmr_hmd.c
··· 1947 1947 wh->base.compute_distortion = compute_distortion_wmr; 1948 1948 u_distortion_mesh_fill_in_compute(&wh->base); 1949 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 + 1950 1962 // Set initial HMD screen power state. 1951 1963 wh->hmd_screen_enable = true; 1952 1964
+49 -29
src/xrt/include/xrt/xrt_compositor.h
··· 1 1 // Copyright 2019-2024, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 858 859 * 859 860 */ 860 861 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 862 enum xrt_compositor_frame_point 871 863 { 872 864 XRT_COMPOSITOR_FRAME_POINT_WOKE, //!< The client woke up after waiting. ··· 974 966 bool fb_face_tracking2_enabled; 975 967 bool meta_body_tracking_full_body_enabled; 976 968 bool meta_body_tracking_calibration_enabled; 969 + bool android_face_tracking_enabled; 977 970 }; 978 971 979 972 /*! ··· 1046 1039 struct xrt_compositor_fence **out_xcf); 1047 1040 1048 1041 /*! 1049 - * Create a compositor semaphore, also returns a native handle. 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 1050 */ 1051 1051 xrt_result_t (*create_semaphore)(struct xrt_compositor *xc, 1052 1052 xrt_graphics_sync_handle_t *out_handle, ··· 2291 2291 *xcn_ptr = NULL; 2292 2292 } 2293 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 + 2294 2326 2295 2327 /* 2296 2328 * ··· 2304 2336 */ 2305 2337 struct xrt_system_compositor_info 2306 2338 { 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. 2339 + uint32_t view_config_count; 2340 + struct xrt_view_config view_configs[XRT_MAX_COMPOSITOR_VIEW_CONFIGS_COUNT]; 2323 2341 2324 2342 //! Maximum number of composition layers supported, never changes. 2325 2343 uint32_t max_layers; ··· 2373 2391 xrt_result_t (*set_state)(struct xrt_system_compositor *xsc, 2374 2392 struct xrt_compositor *xc, 2375 2393 bool visible, 2376 - bool focused); 2394 + bool focused, 2395 + int64_t timestamp_ns); 2377 2396 2378 2397 /*! 2379 2398 * Set the rendering Z order for rendering, visible has higher priority ··· 2473 2492 * @public @memberof xrt_system_compositor 2474 2493 */ 2475 2494 static inline xrt_result_t 2476 - xrt_syscomp_set_state(struct xrt_system_compositor *xsc, struct xrt_compositor *xc, bool visible, bool focused) 2495 + xrt_syscomp_set_state( 2496 + struct xrt_system_compositor *xsc, struct xrt_compositor *xc, bool visible, bool focused, int64_t timestamp_ns) 2477 2497 { 2478 2498 if (xsc->xmcc == NULL) { 2479 2499 return XRT_ERROR_MULTI_SESSION_NOT_IMPLEMENTED; 2480 2500 } 2481 2501 2482 - return xsc->xmcc->set_state(xsc, xc, visible, focused); 2502 + return xsc->xmcc->set_state(xsc, xc, visible, focused, timestamp_ns); 2483 2503 } 2484 2504 2485 2505 /*!
+1
src/xrt/include/xrt/xrt_config_build.h.cmake_in
··· 37 37 #cmakedefine XRT_FEATURE_OPENXR_BODY_TRACKING_FULL_BODY_META 38 38 #cmakedefine XRT_FEATURE_OPENXR_DEBUG_UTILS 39 39 #cmakedefine XRT_FEATURE_OPENXR_DISPLAY_REFRESH_RATE 40 + #cmakedefine XRT_FEATURE_OPENXR_FACE_TRACKING_ANDROID 40 41 #cmakedefine XRT_FEATURE_OPENXR_FACE_TRACKING2_FB 41 42 #cmakedefine XRT_FEATURE_OPENXR_FACIAL_TRACKING_HTC 42 43 #cmakedefine XRT_FEATURE_OPENXR_FORCE_FEEDBACK_CURL
+307 -131
src/xrt/include/xrt/xrt_defines.h
··· 1 1 // Copyright 2019-2024, Collabora, Ltd. 2 + // Copyright 2024-2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 715 716 * 716 717 */ 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 + 718 796 /*! 719 797 * A enum that is used to name devices so that the 720 798 * state trackers can reason about the devices easier. 721 799 */ 722 800 enum xrt_device_name 723 801 { 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, 802 + #define XRT_DEVICE_NAME_TO_ENUM(NAME) NAME, 736 803 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, 804 + XRT_DEVICE_NAME_LIST(XRT_DEVICE_NAME_TO_ENUM) 745 805 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, 806 + #undef XRT_DEVICE_NAME_TO_ENUM 792 807 }; 793 808 794 809 /*! ··· 1117 1132 _(XRT_INPUT_PSSENSE_CIRCLE_TOUCH , XRT_INPUT_NAME(0x030a, BOOLEAN)) \ 1118 1133 _(XRT_INPUT_PSSENSE_SQUEEZE_CLICK , XRT_INPUT_NAME(0x030b, BOOLEAN)) \ 1119 1134 _(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)) \ 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)) \ 1130 1147 \ 1131 1148 /** XR_EXT_hand_interaction */ \ 1132 1149 _(XRT_INPUT_HAND_PINCH_POSE , XRT_INPUT_NAME(0x0401, POSE)) \ ··· 1164 1181 _(XRT_INPUT_HTC_LIP_FACE_TRACKING , XRT_INPUT_NAME(0x0602, FACE_TRACKING)) \ 1165 1182 _(XRT_INPUT_FB_FACE_TRACKING2_AUDIO , XRT_INPUT_NAME(0x0603, FACE_TRACKING)) \ 1166 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)) \ 1167 1185 \ 1168 1186 _(XRT_INPUT_GENERIC_BODY_TRACKING , XRT_INPUT_NAME(0x0700, BODY_TRACKING)) \ 1169 1187 _(XRT_INPUT_FB_BODY_TRACKING , XRT_INPUT_NAME(0x0701, BODY_TRACKING)) \ ··· 1318 1336 \ 1319 1337 _(XRT_INPUT_BLUBUR_S1_MENU_CLICK , XRT_INPUT_NAME(0x1000, BOOLEAN)) \ 1320 1338 \ 1321 - _(XRT_INPUT_PSVR2_SYSTEM_CLICK , XRT_INPUT_NAME(0x1100, BOOLEAN)) 1322 - 1323 - 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. */ 1324 1347 // clang-format on 1325 1348 1326 1349 ··· 1470 1493 #define XRT_OUTPUT_TYPE_BITMASK 0xffu 1471 1494 1472 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 + /*! 1473 1531 * Base type of this output. 1474 1532 * 1475 1533 * @ingroup xrt_iface ··· 1482 1540 // clang-format on 1483 1541 }; 1484 1542 1485 - #define XRT_OUTPUT_NAME(id, type) ((UINT32_C(id) << XRT_OUTPUT_TYPE_BITWIDTH) | (uint32_t)XRT_OUTPUT_TYPE_##type) 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 + }; 1486 1602 1487 1603 enum xrt_face_expression2_fb 1488 1604 { ··· 1649 1765 #define XRT_FACIAL_EXPRESSION_EYE_COUNT_HTC 14 1650 1766 #define XRT_FACIAL_EXPRESSION_LIP_COUNT_HTC 37 1651 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 + 1652 1858 struct xrt_facial_base_expression_set_htc 1653 1859 { 1654 1860 int64_t sample_time_ns; ··· 1681 1887 bool is_eye_following_blendshapes_valid; 1682 1888 }; 1683 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 + 1684 1901 struct xrt_facial_expression_set 1685 1902 { 1686 1903 union { ··· 1688 1905 struct xrt_facial_eye_expression_set_htc eye_expression_set_htc; 1689 1906 struct xrt_facial_lip_expression_set_htc lip_expression_set_htc; 1690 1907 struct xrt_facial_expression_set2_fb face_expression_set2_fb; 1908 + struct xrt_facial_expression_set_android face_expression_set_android; 1691 1909 }; 1692 1910 }; 1693 1911 ··· 1958 2176 }; 1959 2177 1960 2178 /*! 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 2179 * Value used to indicate a haptic pulse of the minimal supported duration. 2013 2180 * 2014 2181 * @ingroup xrt_iface ··· 2107 2274 { 2108 2275 XRT_FORM_FACTOR_HMD, //!< Head mounted display. 2109 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, 2110 2286 }; 2111 2287 2112 2288 /*!
+55 -22
src/xrt/include/xrt/xrt_device.h
··· 103 103 //! Nominal frame interval 104 104 uint64_t nominal_frame_interval_ns; 105 105 enum xrt_scanout_direction scanout_direction; 106 - uint64_t scanout_time_ns; 106 + int64_t scanout_time_ns; 107 107 } screens[1]; 108 108 109 109 /*! ··· 406 406 struct xrt_facial_expression_set *out_value); 407 407 408 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 + /*! 409 419 * @brief Get the body skeleton in T-pose, used to query the skeleton hierarchy, scale, proportions etc 410 420 * 411 421 * @param[in] xdev The device. ··· 489 499 * @param[out] out_plane_detection_id The id of the new plane detection request generated by the xdev. 490 500 * @return generally XRT_SUCCESS, except for internal runtime failures. 491 501 */ 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); 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); 496 506 497 507 /*! 498 508 * Destroy internal resources associated with plane_detector_id. ··· 501 511 * @param[in] plane_detection_id An id generated by the xdev. 502 512 * @return generally XRT_SUCCESS, except for internal runtime failures. 503 513 */ 504 - enum xrt_result (*destroy_plane_detection_ext)(struct xrt_device *xdev, uint64_t plane_detection_id); 514 + xrt_result_t (*destroy_plane_detection_ext)(struct xrt_device *xdev, uint64_t plane_detection_id); 505 515 506 516 /*! 507 517 * Get the state of a plane detection request. ··· 511 521 * @param[out] out_state The state of the plane detection. 512 522 * @return generally XRT_SUCCESS, except for internal runtime failures. 513 523 */ 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); 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); 517 527 518 528 /*! 519 529 * Get results of a plane detection request. ··· 523 533 * @param[out] detections The detected planes, if any. 524 534 * @return generally XRT_SUCCESS, except for internal runtime failures. 525 535 */ 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); 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); 529 539 530 540 /*! 531 541 * @brief Get the per-view pose in relation to the view space. ··· 550 560 * input. 551 561 * @param[in] at_timestamp_ns This is when the caller wants the poses and FOVs to be from. 552 562 * @param[in] view_count Number of views. 563 + * @param[in] view_type Type of view configuration (mono or stereo). 553 564 * @param[out] out_head_relation 554 565 * The head pose in the device tracking space. 555 566 * Combine with @p out_poses to get the views in ··· 567 578 xrt_result_t (*get_view_poses)(struct xrt_device *xdev, 568 579 const struct xrt_vec3 *default_eye_relation, 569 580 int64_t at_timestamp_ns, 581 + enum xrt_view_type view_type, 570 582 uint32_t view_count, 571 583 struct xrt_space_relation *out_head_relation, 572 584 struct xrt_fov *out_fovs, ··· 754 766 } 755 767 756 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 + /*! 757 782 * Helper function for @ref xrt_device::get_body_skeleton. 758 783 * 759 784 * @copydoc xrt_device::get_body_skeleton ··· 858 883 } 859 884 860 885 /*! 861 - * Helper function for @ref xrt_device::begin_plane_detection. 886 + * Helper function for @ref xrt_device::begin_plane_detection_ext. 862 887 * 863 888 * @public @memberof xrt_device 864 889 */ 865 - static inline enum xrt_result 890 + static inline xrt_result_t 866 891 xrt_device_begin_plane_detection_ext(struct xrt_device *xdev, 867 892 const struct xrt_plane_detector_begin_info_ext *begin_info, 868 893 uint64_t plane_detection_id, ··· 872 897 } 873 898 874 899 /*! 875 - * Helper function for @ref xrt_device::destroy_plane_detection. 900 + * Helper function for @ref xrt_device::destroy_plane_detection_ext. 876 901 * 877 902 * @public @memberof xrt_device 878 903 */ 879 - static inline enum xrt_result 904 + static inline xrt_result_t 880 905 xrt_device_destroy_plane_detection_ext(struct xrt_device *xdev, uint64_t plane_detection_id) 881 906 { 882 907 return xdev->destroy_plane_detection_ext(xdev, plane_detection_id); 883 908 } 884 909 885 910 /*! 886 - * Helper function for @ref xrt_device::get_plane_detections. 911 + * Helper function for @ref xrt_device::get_plane_detections_ext. 887 912 * 888 913 * @public @memberof xrt_device 889 914 */ 890 - static inline enum xrt_result 915 + static inline xrt_result_t 891 916 xrt_device_get_plane_detection_state_ext(struct xrt_device *xdev, 892 917 uint64_t plane_detection_id, 893 918 enum xrt_plane_detector_state_ext *out_state) ··· 896 921 } 897 922 898 923 /*! 899 - * Helper function for @ref xrt_device::get_plane_detections. 924 + * Helper function for @ref xrt_device::get_plane_detections_ext. 900 925 * 901 926 * @public @memberof xrt_device 902 927 */ 903 - static inline enum xrt_result 928 + static inline xrt_result_t 904 929 xrt_device_get_plane_detections_ext(struct xrt_device *xdev, 905 930 uint64_t plane_detection_id, 906 931 struct xrt_plane_detections_ext *out_detections) ··· 918 943 xrt_device_get_view_poses(struct xrt_device *xdev, 919 944 const struct xrt_vec3 *default_eye_relation, 920 945 int64_t at_timestamp_ns, 946 + enum xrt_view_type view_type, 921 947 uint32_t view_count, 922 948 struct xrt_space_relation *out_head_relation, 923 949 struct xrt_fov *out_fovs, 924 950 struct xrt_pose *out_poses) 925 951 { 926 - return xdev->get_view_poses(xdev, default_eye_relation, at_timestamp_ns, view_count, out_head_relation, 927 - out_fovs, out_poses); 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); // 928 961 } 929 962 930 963 /*!
+21
src/xrt/include/xrt/xrt_instance.h
··· 1 1 // Copyright 2020-2024, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 81 82 bool fb_face_tracking2_enabled; 82 83 bool meta_body_tracking_full_body_enabled; 83 84 bool meta_body_tracking_calibration_enabled; 85 + bool android_face_tracking_enabled; 84 86 }; 85 87 86 88 /*! ··· 126 128 */ 127 129 128 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 + /*! 129 136 * Creates all of the system resources like the devices and system 130 137 * compositor. The system compositor is optional. 131 138 * ··· 198 205 */ 199 206 struct xrt_instance_android *android_instance; 200 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 + } 201 222 202 223 /*! 203 224 * @copydoc xrt_instance::create_system
+18
src/xrt/include/xrt/xrt_limits.h
··· 1 1 // Copyright 2019-2022, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 9 10 10 11 #pragma once 11 12 13 + #include "xrt/xrt_config_os.h" 12 14 #include "xrt/xrt_compiler.h" 13 15 14 16 ··· 20 22 * Max number of views supported by a compositor, artificial limit. 21 23 */ 22 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 23 35 24 36 /*! 25 37 * Maximum number of handles sent in one call. ··· 61 73 /*! 62 74 * Max number of layers which can be handled at once. 63 75 */ 76 + #ifdef XRT_OS_ANDROID 77 + #define XRT_MAX_LAYERS 32 78 + #elif defined(XRT_OS_LINUX) || defined(XRT_OS_WINDOWS) 64 79 #define XRT_MAX_LAYERS 128 80 + #else 81 + #error "Unknown platform, define XRT_MAX_LAYERS for your OS" 82 + #endif 65 83 66 84 /*! 67 85 * @}
+6
src/xrt/include/xrt/xrt_results.h
··· 251 251 * Invoking complete on an already completed future 252 252 */ 253 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, 254 260 } xrt_result_t;
+1
src/xrt/include/xrt/xrt_session.h
··· 80 80 enum xrt_session_event_type type; 81 81 bool visible; 82 82 bool focused; 83 + int64_t timestamp_ns; 83 84 }; 84 85 85 86 /*!
+80
src/xrt/include/xrt/xrt_space.h
··· 1 1 // Copyright 2019-2023, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 303 304 struct xrt_space **out_local_space, 304 305 struct xrt_space **out_local_floor_space); 305 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 + 306 360 /*! 307 361 * Destroy function. 308 362 * ··· 513 567 struct xrt_space **out_local_floor_space) 514 568 { 515 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); 516 596 } 517 597 518 598 /*!
+4
src/xrt/include/xrt/xrt_tracking.h
··· 1 1 // Copyright 2019, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 60 61 61 62 // The device(s) are tracked by other methods. 62 63 XRT_TRACKING_TYPE_OTHER, 64 + 65 + // The device(s) are (re)attachable. 66 + XRT_TRACKING_TYPE_ATTACHABLE, 63 67 }; 64 68 65 69 /*!
+32 -3
src/xrt/ipc/CMakeLists.txt
··· 1 1 # Copyright 2020-2021, Collabora, Ltd. 2 + # Copyright 2025, NVIDIA CORPORATION. 2 3 # SPDX-License-Identifier: BSL-1.0 3 4 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 + ### 5 18 # Generator 6 19 7 20 foreach( ··· 16 29 OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${fn}" 17 30 COMMAND 18 31 ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/shared/proto.py 19 - ${CMAKE_CURRENT_SOURCE_DIR}/shared/proto.json 20 - "${CMAKE_CURRENT_BINARY_DIR}/${fn}" 32 + ${CMAKE_CURRENT_BINARY_DIR}/proto.json "${CMAKE_CURRENT_BINARY_DIR}/${fn}" 21 33 VERBATIM 22 34 DEPENDS 23 35 ${CMAKE_CURRENT_SOURCE_DIR}/shared/proto.py 24 36 ${CMAKE_CURRENT_SOURCE_DIR}/shared/ipcproto/common.py 25 - ${CMAKE_CURRENT_SOURCE_DIR}/shared/proto.json 37 + ${CMAKE_CURRENT_BINARY_DIR}/proto.json 38 + ${CMAKE_CURRENT_SOURCE_DIR}/shared/ipc_protocol_generated.h.template 26 39 COMMENT "Generating ${fn} from protocol JSON description" 27 40 ) 28 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") 29 58 30 59 set(IPC_COMMON_SOURCES 31 60 ${CMAKE_CURRENT_BINARY_DIR}/ipc_protocol_generated.h
+24 -1
src/xrt/ipc/client/ipc_client.h
··· 1 1 // Copyright 2020-2023, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 16 17 17 18 #include "util/u_threading.h" 18 19 #include "util/u_logging.h" 20 + #include "util/u_system_helpers.h" 19 21 20 22 #include "shared/ipc_utils.h" 21 23 #include "shared/ipc_protocol.h" ··· 69 71 #endif // XRT_OS_ANDROID 70 72 }; 71 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 + 72 92 73 93 /* 74 94 * ··· 125 145 struct xrt_space_overseer * 126 146 ipc_client_space_overseer_create(struct ipc_connection *ipc_c); 127 147 128 - struct xrt_system_devices * 148 + uint32_t 149 + ipc_client_space_get_id(struct xrt_space *space); 150 + 151 + struct ipc_client_system_devices * 129 152 ipc_client_system_devices_create(struct ipc_connection *ipc_c); 130 153 131 154 struct xrt_session *
+12 -1
src/xrt/ipc/client/ipc_client_compositor.c
··· 1 1 // Copyright 2020, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 288 289 &use_dedicated_allocation, // out 289 290 remote_handles, // handles 290 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 + } 291 297 IPC_CHK_AND_RET(icc->ipc_c, xret, "ipc_call_swapchain_create"); 292 298 293 299 struct ipc_client_swapchain *ics = U_TYPED_CALLOC(struct ipc_client_swapchain); ··· 345 351 handles, // handles 346 352 image_count, // handles 347 353 &id); // out 348 - IPC_CHK_AND_RET(icc->ipc_c, xret, "ipc_call_swapchain_create"); 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"); 349 360 350 361 struct ipc_client_swapchain *ics = U_TYPED_CALLOC(struct ipc_client_swapchain); 351 362 ics->base.base.image_count = image_count;
+1 -4
src/xrt/ipc/client/ipc_client_device.c
··· 86 86 ipc_client_device_t *icd = U_DEVICE_ALLOCATE(ipc_client_device_t, flags, 0, 0); 87 87 88 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; 89 + ipc_client_xdev_init(icd, ipc_c, xtrack, device_id, ipc_client_device_destroy); 93 90 94 91 // Setup variable tracker. 95 92 u_var_add_root(icd, icd->base.str, true);
+6 -2
src/xrt/ipc/client/ipc_client_hmd.c
··· 66 66 call_get_view_poses_raw(ipc_client_hmd_t *ich, 67 67 const struct xrt_vec3 *default_eye_relation, 68 68 int64_t at_timestamp_ns, 69 + enum xrt_view_type view_type, 69 70 uint32_t view_count, 70 71 struct xrt_space_relation *out_head_relation, 71 72 struct xrt_fov *out_fovs, ··· 82 83 ich->device_id, // 83 84 default_eye_relation, // 84 85 at_timestamp_ns, // 86 + view_type, // 85 87 view_count); // 86 88 IPC_CHK_WITH_GOTO(ich->ipc_c, xret, "ipc_send_device_get_view_poses_locked", out); 87 89 ··· 131 133 ipc_client_hmd_get_view_poses(struct xrt_device *xdev, 132 134 const struct xrt_vec3 *default_eye_relation, 133 135 int64_t at_timestamp_ns, 136 + enum xrt_view_type view_type, 134 137 uint32_t view_count, 135 138 struct xrt_space_relation *out_head_relation, 136 139 struct xrt_fov *out_fovs, ··· 148 151 ich->device_id, // 149 152 default_eye_relation, // 150 153 at_timestamp_ns, // 154 + view_type, // 151 155 view_count, // 152 156 &info); // 153 157 IPC_CHK_AND_RET(ich->ipc_c, xret, "ipc_call_device_get_view_poses_2"); ··· 164 168 ich, // 165 169 default_eye_relation, // 166 170 at_timestamp_ns, // 171 + view_type, // 167 172 view_count, // 168 173 out_head_relation, // 169 174 out_fovs, // ··· 316 321 ipc_client_hmd_t *ich = U_DEVICE_ALLOCATE(ipc_client_hmd_t, flags, 0, 0); 317 322 318 323 // Fills in almost everything a regular device needs. 319 - ipc_client_xdev_init(ich, ipc_c, xtrack, device_id); 324 + ipc_client_xdev_init(ich, ipc_c, xtrack, device_id, ipc_client_hmd_destroy); 320 325 321 326 // Fill in needed HMD functions, and destroy. 322 327 ich->base.get_view_poses = ipc_client_hmd_get_view_poses; 323 328 ich->base.compute_distortion = ipc_client_hmd_compute_distortion; 324 329 ich->base.is_form_factor_available = ipc_client_hmd_is_form_factor_available; 325 330 ich->base.get_visibility_mask = ipc_client_hmd_get_visibility_mask; 326 - ich->base.destroy = ipc_client_hmd_destroy; 327 331 ich->base.get_brightness = ipc_client_hmd_get_brightness; 328 332 ich->base.set_brightness = ipc_client_hmd_set_brightness; 329 333
+45 -58
src/xrt/ipc/client/ipc_client_instance.c
··· 1 1 // Copyright 2020-2024, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 78 79 79 80 struct ipc_connection ipc_c; 80 81 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 82 #ifdef XRT_OS_ANDROID 88 83 struct android_instance_base android; 89 84 #endif ··· 136 131 */ 137 132 138 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 139 142 ipc_client_instance_create_system(struct xrt_instance *xinst, 140 143 struct xrt_system **out_xsys, 141 144 struct xrt_system_devices **out_xsysd, ··· 151 154 assert(*out_xsysd == NULL); 152 155 assert(out_xsysc == NULL || *out_xsysc == NULL); 153 156 154 - struct xrt_system_devices *xsysd = NULL; 155 157 struct xrt_system_compositor *xsysc = NULL; 156 158 157 159 // Allocate a helper xrt_system_devices struct. 158 - xsysd = ipc_client_system_devices_create(&ii->ipc_c); 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; 159 166 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; 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 + } 164 195 } 165 - xsysd->xdev_count = ii->xdev_count; 166 - ii->xdev_count = 0; 196 + xsysd->xdev_count = count; 167 197 168 198 #define SET_ROLE(ROLE) \ 169 199 do { \ ··· 231 261 232 262 // service considers us to be connected until fd is closed 233 263 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 264 242 265 #ifdef XRT_OS_ANDROID 243 266 android_instance_base_cleanup(&(ii->android), xinst); ··· 269 292 ipc_instance_create(const struct xrt_instance_info *i_info, struct xrt_instance **out_xinst) 270 293 { 271 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; 272 296 ii->base.create_system = ipc_client_instance_create_system; 273 297 ii->base.get_prober = ipc_client_instance_get_prober; 274 298 ii->base.destroy = ipc_client_instance_destroy; ··· 294 318 free(ii); 295 319 return xret; 296 320 } 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 321 335 322 ii->base.startup_timestamp = ii->ipc_c.ism->startup_timestamp; 336 323
+25
src/xrt/ipc/client/ipc_client_space_overseer.c
··· 1 1 // Copyright 2023, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 317 318 return ipc_call_space_set_reference_space_offset(icspo->ipc_c, type, offset); 318 319 } 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 + 320 335 static void 321 336 destroy(struct xrt_space_overseer *xso) 322 337 { ··· 373 388 icspo->base.set_tracking_origin_offset = set_tracking_origin_offset; 374 389 icspo->base.get_reference_space_offset = get_reference_space_offset; 375 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; 376 393 icspo->base.destroy = destroy; 377 394 icspo->ipc_c = ipc_c; 378 395 ··· 395 412 396 413 return &icspo->base; 397 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 1 // Copyright 2020-2023, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 135 136 ipc_client_system_create(struct ipc_connection *ipc_c, struct xrt_system_compositor *xsysc) 136 137 { 137 138 struct ipc_client_system *icsys = U_TYPED_CALLOC(struct ipc_client_system); 139 + 138 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"); 139 142 if (xret != XRT_SUCCESS) { 140 143 free(icsys); 141 144 return NULL;
+11 -14
src/xrt/ipc/client/ipc_client_system_devices.c
··· 1 1 // Copyright 2023, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 12 13 #include "ipc_client_generated.h" 13 14 14 15 #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 - }; 16 + #include "util/u_var.h" 27 17 28 18 29 19 /* ··· 93 83 { 94 84 struct ipc_client_system_devices *usysd = ipc_system_devices(xsysd); 95 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 + 96 93 u_system_devices_close(&usysd->base.base); 97 94 98 95 free(usysd); ··· 105 102 * 106 103 */ 107 104 108 - struct xrt_system_devices * 105 + struct ipc_client_system_devices * 109 106 ipc_client_system_devices_create(struct ipc_connection *ipc_c) 110 107 { 111 108 struct ipc_client_system_devices *icsd = U_TYPED_CALLOC(struct ipc_client_system_devices); ··· 115 112 icsd->base.base.feature_dec = ipc_client_system_devices_feature_dec; 116 113 icsd->ipc_c = ipc_c; 117 114 118 - return &icsd->base.base; 115 + return icsd; 119 116 }
+8 -9
src/xrt/ipc/client/ipc_client_xdev.c
··· 391 391 ipc_client_xdev_init(struct ipc_client_xdev *icx, 392 392 struct ipc_connection *ipc_c, 393 393 struct xrt_tracking_origin *xtrack, 394 - uint32_t device_id) 394 + uint32_t device_id, 395 + u_device_destroy_function_t destroy_fn) 395 396 { 396 397 // Helpers. 397 398 struct ipc_shared_memory *ism = ipc_c->ism; ··· 400 401 // Important fields. 401 402 icx->ipc_c = ipc_c; 402 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); 403 410 404 411 // Shared implemented functions. 405 412 icx->base.update_inputs = ipc_client_xdev_update_inputs; 406 - icx->base.get_tracked_pose = ipc_client_xdev_get_tracked_pose; 407 413 icx->base.get_hand_tracking = ipc_client_xdev_get_hand_tracking; 408 414 icx->base.get_face_tracking = ipc_client_xdev_get_face_tracking; 409 415 icx->base.get_body_skeleton = ipc_client_xdev_get_body_skeleton; ··· 420 426 icx->base.destroy_plane_detection_ext = ipc_client_xdev_destroy_plane_detection_ext; 421 427 icx->base.get_plane_detection_state_ext = ipc_client_xdev_get_plane_detection_state_ext; 422 428 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 429 431 430 // Copying the information from the isdev. 432 431 icx->base.device_type = isdev->device_type;
+5 -1
src/xrt/ipc/client/ipc_client_xdev.h
··· 13 13 14 14 #pragma once 15 15 16 + #include "util/u_device.h" 17 + 18 + 16 19 #ifdef __cplusplus 17 20 extern "C" { 18 21 #endif ··· 58 61 ipc_client_xdev_init(struct ipc_client_xdev *icx, 59 62 struct ipc_connection *ipc_c, 60 63 struct xrt_tracking_origin *xtrack, 61 - uint32_t device_id); 64 + uint32_t device_id, 65 + u_device_destroy_function_t destroy_fn); 62 66 63 67 /*! 64 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 1 // Copyright 2020-2023, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 22 23 23 24 #include "shared/ipc_protocol.h" 24 25 #include "shared/ipc_message_channel.h" 26 + 27 + #include "ipc_server_interface.h" 25 28 26 29 #include <stdio.h> 27 30 ··· 89 92 { 90 93 //! Link back to the main server. 91 94 struct ipc_server *server; 95 + 96 + //! Has the system part of the shm initialized. 97 + bool has_init_shm_system; 92 98 93 99 //! Session for this client. 94 100 struct xrt_session *xs; ··· 188 194 { 189 195 //! The actual device. 190 196 struct xrt_device *xdev; 191 - 192 - //! Is the IO suppressed for this device. 193 - bool io_active; 194 197 }; 195 198 196 199 /*! ··· 329 332 * @public @memberof ipc_server_mainloop 330 333 */ 331 334 int 332 - ipc_server_mainloop_init(struct ipc_server_mainloop *ml); 335 + ipc_server_mainloop_init(struct ipc_server_mainloop *ml, bool no_stdin); 333 336 334 337 /*! 335 338 * @brief Poll the mainloop. ··· 407 410 408 411 struct os_mutex lock; 409 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; 410 426 }; 411 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); 412 437 413 438 /*! 414 439 * Get the current state of a client.
+41 -17
src/xrt/ipc/server/ipc_server_handler.c
··· 1 1 // Copyright 2020-2024, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 387 388 EXT(meta_body_tracking_full_body_enabled); 388 389 EXT(meta_body_tracking_calibration_enabled); 389 390 EXT(fb_face_tracking2_enabled); 391 + EXT(android_face_tracking_enabled); 390 392 391 393 #undef EXT 392 394 #undef PTT ··· 400 402 } 401 403 402 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 403 424 ipc_handle_system_compositor_get_info(volatile struct ipc_client_state *ics, 404 425 struct xrt_system_compositor_info *out_info) 405 426 { ··· 440 461 ics->xc = &xcn->base; 441 462 442 463 xrt_syscomp_set_state(ics->server->xsysc, ics->xc, ics->client_state.session_visible, 443 - ics->client_state.session_focused); 464 + ics->client_state.session_focused, os_monotonic_get_ns()); 444 465 xrt_syscomp_set_z_order(ics->server->xsysc, ics->xc, ics->client_state.z_order); 445 466 446 467 return XRT_SUCCESS; ··· 485 506 .fb_face_tracking2_enabled = ics->client_state.info.fb_face_tracking2_enabled, 486 507 .meta_body_tracking_full_body_enabled = ics->client_state.info.meta_body_tracking_full_body_enabled, 487 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, 488 510 }; 489 511 490 512 return xrt_comp_begin_session(ics->xc, &begin_session_info); ··· 1623 1645 } 1624 1646 1625 1647 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 1648 ipc_handle_swapchain_get_properties(volatile struct ipc_client_state *ics, 1641 1649 const struct xrt_swapchain_create_info *info, 1642 1650 struct xrt_swapchain_create_properties *xsccp) ··· 1931 1939 struct xrt_input *dst = &ism->inputs[isdev->first_input_index]; 1932 1940 size_t size = sizeof(struct xrt_input) * isdev->input_count; 1933 1941 1934 - bool io_active = ics->io_active && idev->io_active; 1942 + bool io_active = ics->io_active; 1935 1943 if (io_active) { 1936 1944 memcpy(dst, src, size); 1937 1945 } else { ··· 1986 1994 } 1987 1995 1988 1996 // Special case the headpose. 1989 - bool disabled = (!isdev->io_active || !ics->io_active) && name != XRT_INPUT_GENERIC_HEAD_POSE; 1997 + bool disabled = !ics->io_active && name != XRT_INPUT_GENERIC_HEAD_POSE; 1990 1998 bool active_on_client = input->active; 1991 1999 1992 2000 // We have been disabled but the client hasn't called update. ··· 2026 2034 uint32_t id, 2027 2035 const struct xrt_vec3 *fallback_eye_relation, 2028 2036 int64_t at_timestamp_ns, 2037 + enum xrt_view_type view_type, 2029 2038 uint32_t view_count) 2030 2039 { 2031 2040 struct ipc_message_channel *imc = (struct ipc_message_channel *)&ics->imc; ··· 2055 2064 xdev, // 2056 2065 fallback_eye_relation, // 2057 2066 at_timestamp_ns, // 2067 + view_type, // 2058 2068 view_count, // 2059 2069 &reply.head_relation, // 2060 2070 fovs, // ··· 2100 2110 uint32_t id, 2101 2111 const struct xrt_vec3 *default_eye_relation, 2102 2112 int64_t at_timestamp_ns, 2113 + enum xrt_view_type view_type, 2103 2114 uint32_t view_count, 2104 2115 struct ipc_info_get_view_poses_2 *out_info) 2105 2116 { ··· 2107 2118 uint32_t device_id = id; 2108 2119 struct xrt_device *xdev = NULL; 2109 2120 GET_XDEV_OR_RETURN(ics, device_id, xdev); 2121 + 2110 2122 return xrt_device_get_view_poses( // 2111 2123 xdev, // 2112 2124 default_eye_relation, // 2113 2125 at_timestamp_ns, // 2126 + view_type, // 2114 2127 view_count, // 2115 2128 &out_info->head_relation, // 2116 2129 out_info->fovs, // ··· 2556 2569 GET_XDEV_OR_RETURN(ics, device_id, xdev); 2557 2570 // Get facial expression data. 2558 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); 2559 2583 } 2560 2584 2561 2585 xrt_result_t
+32
src/xrt/ipc/server/ipc_server_interface.h
··· 36 36 { 37 37 //! Information passed onto the debug gui. 38 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; 39 45 }; 40 46 41 47 /*! ··· 70 76 * @param[in] data User data given passed into the main function. 71 77 */ 72 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); 73 97 }; 74 98 75 99 /*! ··· 80 104 int 81 105 ipc_server_main_common(const struct ipc_server_main_info *ismi, const struct ipc_server_callbacks *iscb, void *data); 82 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); 83 115 84 116 #ifndef XRT_OS_ANDROID 85 117
+1 -1
src/xrt/ipc/server/ipc_server_mainloop_android.c
··· 139 139 } 140 140 141 141 int 142 - ipc_server_mainloop_init(struct ipc_server_mainloop *ml) 142 + ipc_server_mainloop_init(struct ipc_server_mainloop *ml, bool no_stdin) 143 143 { 144 144 int ret = init_pipe(ml); 145 145 if (ret < 0) {
+5 -12
src/xrt/ipc/server/ipc_server_mainloop_linux.c
··· 1 1 // Copyright 2020-2021, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 46 47 #include <systemd/sd-daemon.h> 47 48 #endif 48 49 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 50 58 51 /* 59 52 * ··· 175 168 } 176 169 177 170 static int 178 - init_epoll(struct ipc_server_mainloop *ml) 171 + init_epoll(struct ipc_server_mainloop *ml, bool no_stdin) 179 172 { 180 173 int ret = epoll_create1(EPOLL_CLOEXEC); 181 174 if (ret < 0) { ··· 186 179 187 180 struct epoll_event ev = {0}; 188 181 189 - if (!ml->launched_by_socket && !debug_get_bool_option_skip_stdin()) { 182 + if (!ml->launched_by_socket && !no_stdin) { 190 183 // Can't do this when launched by systemd socket activation by 191 184 // default. 192 185 // This polls stdin. ··· 265 258 } 266 259 267 260 int 268 - ipc_server_mainloop_init(struct ipc_server_mainloop *ml) 261 + ipc_server_mainloop_init(struct ipc_server_mainloop *ml, bool no_stdin) 269 262 { 270 263 IPC_TRACE_MARKER(); 271 264 ··· 275 268 return ret; 276 269 } 277 270 278 - ret = init_epoll(ml); 271 + ret = init_epoll(ml, no_stdin); 279 272 if (ret < 0) { 280 273 ipc_server_mainloop_deinit(ml); 281 274 return ret;
+3 -2
src/xrt/ipc/server/ipc_server_mainloop_windows.cpp
··· 1 1 // Copyright 2022, Magic Leap, Inc. 2 2 // Copyright 2020-2022, Collabora, Ltd. 3 + // Copyright 2025, NVIDIA CORPORATION. 3 4 // SPDX-License-Identifier: BSL-1.0 4 5 /*! 5 6 * @file ··· 218 219 { 219 220 IPC_TRACE_MARKER(); 220 221 221 - if (_kbhit()) { 222 + if (!vs->no_stdin && _kbhit()) { 222 223 U_LOG_E("console input! exiting..."); 223 224 ipc_server_handle_shutdown_signal(vs); 224 225 return; ··· 249 250 } 250 251 251 252 int 252 - ipc_server_mainloop_init(struct ipc_server_mainloop *ml) 253 + ipc_server_mainloop_init(struct ipc_server_mainloop *ml, bool no_stdin) 253 254 { 254 255 IPC_TRACE_MARKER(); 255 256
+29 -3
src/xrt/ipc/server/ipc_server_per_client_thread.c
··· 1 1 // Copyright 2020-2023, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 200 201 { 201 202 U_TRACE_SET_THREAD_NAME("IPC Client"); 202 203 203 - IPC_INFO(ics->server, "Client %u connected", ics->client_state.id); 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); // 204 209 205 210 // Claim the client fd. 206 211 int epoll_fd = setup_epoll(ics); ··· 231 236 232 237 // Detect clients disconnecting gracefully. 233 238 if (ret > 0 && (event.events & EPOLLHUP) != 0) { 234 - IPC_INFO(ics->server, "Client disconnected."); 235 239 break; 236 240 } 237 241 ··· 249 253 break; 250 254 } 251 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 + 252 262 // Read the whole command now that we know its size 253 263 uint8_t buf[IPC_BUF_SIZE] = {0}; 254 264 ··· 274 284 close(epoll_fd); 275 285 epoll_fd = -1; 276 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 + 277 293 // Following code is same for all platforms. 278 294 common_shutdown(ics); 279 295 } ··· 297 313 { 298 314 U_TRACE_SET_THREAD_NAME("IPC Client"); 299 315 300 - IPC_INFO(ics->server, "Client connected"); 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); // 301 321 302 322 while (ics->server->running) { 303 323 uint8_t buf[IPC_BUF_SIZE] = {0}; ··· 353 373 break; 354 374 } 355 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); // 356 382 357 383 // Following code is same for all platforms. 358 384 common_shutdown(ics);
+164 -48
src/xrt/ipc/server/ipc_server_process.c
··· 57 57 * 58 58 */ 59 59 60 - DEBUG_GET_ONCE_BOOL_OPTION(exit_on_disconnect, "IPC_EXIT_ON_DISCONNECT", false) 61 60 DEBUG_GET_ONCE_BOOL_OPTION(exit_when_idle, "IPC_EXIT_WHEN_IDLE", false) 62 61 DEBUG_GET_ONCE_NUM_OPTION(exit_when_idle_delay_ms, "IPC_EXIT_WHEN_IDLE_DELAY_MS", 5000) 63 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) 64 72 65 73 66 74 /* ··· 90 98 static void 91 99 init_idev(struct ipc_device *idev, struct xrt_device *xdev) 92 100 { 93 - if (xdev != NULL) { 94 - idev->io_active = true; 95 - idev->xdev = xdev; 96 - } else { 97 - idev->io_active = false; 98 - } 101 + idev->xdev = xdev; 99 102 } 100 103 101 104 static void 102 105 teardown_idev(struct ipc_device *idev) 103 106 { 104 - idev->io_active = false; 107 + idev->xdev = NULL; 105 108 } 106 109 107 110 static void ··· 280 283 } 281 284 282 285 XRT_CHECK_RESULT static xrt_result_t 283 - init_shm(struct ipc_server *s, volatile struct ipc_client_state *cs) 286 + init_shm_and_instance_state(struct ipc_server *s, volatile struct ipc_client_state *ics) 284 287 { 285 288 const size_t size = sizeof(struct ipc_shared_memory); 286 289 xrt_shmem_handle_t handle; 287 290 288 - xrt_result_t xret = ipc_shmem_create(size, &handle, (void **)&s->isms[cs->server_thread_index]); 291 + xrt_result_t xret = ipc_shmem_create(size, &handle, (void **)&s->isms[ics->server_thread_index]); 289 292 IPC_CHK_AND_RET(s, xret, "ipc_shmem_create"); 290 293 291 294 // we have a filehandle, we will pass this to our client 292 - cs->ism_handle = handle; 295 + ics->ism_handle = handle; 296 + 297 + // Convenience 298 + struct ipc_shared_memory *ism = s->isms[ics->server_thread_index]; 293 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); 294 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 + { 295 312 /* 296 313 * 297 314 * Setup the shared memory state. ··· 300 317 301 318 uint32_t count = 0; 302 319 struct ipc_shared_memory *ism = s->isms[cs->server_thread_index]; 303 - 304 - ism->startup_timestamp = os_monotonic_get_ns(); 305 320 306 321 // Setup the tracking origins. 307 322 count = 0; ··· 402 417 403 418 // Setup the HMD 404 419 // 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 - } 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 + } 411 429 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]; 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; 416 436 } 417 - ism->hmd.blend_mode_count = s->xsysd->static_roles.head->hmd->blend_mode_count; 418 437 419 438 // Finally tell the client how many devices we have. 420 439 ism->isdev_count = count; ··· 424 443 ism->roles.eyes = find_xdev_index(s, s->xsysd->static_roles.eyes); 425 444 ism->roles.face = find_xdev_index(s, s->xsysd->static_roles.face); 426 445 ism->roles.body = find_xdev_index(s, s->xsysd->static_roles.body); 446 + 427 447 #define SET_HT_ROLE(SRC) \ 428 448 ism->roles.hand_tracking.SRC.left = find_xdev_index(s, s->xsysd->static_roles.hand_tracking.SRC.left); \ 429 449 ism->roles.hand_tracking.SRC.right = find_xdev_index(s, s->xsysd->static_roles.hand_tracking.SRC.right); 430 450 SET_HT_ROLE(unobstructed) 431 451 SET_HT_ROLE(conforming) 432 452 #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 453 } 439 454 440 455 static void ··· 455 470 } 456 471 457 472 static xrt_result_t 458 - init_all(struct ipc_server *s, enum u_logging_level log_level) 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) 459 478 { 460 479 xrt_result_t xret = XRT_SUCCESS; 461 480 int ret; ··· 463 482 // First order of business set the log level. 464 483 s->log_level = log_level; 465 484 485 + // Store callbacks and data 486 + s->callbacks = callbacks; 487 + s->callback_data = callback_data; 488 + 466 489 // This should never fail. 467 490 ret = os_mutex_init(&s->global_state.lock); 468 491 if (ret < 0) { ··· 480 503 481 504 // Yes we should be running. 482 505 s->running = true; 483 - s->exit_on_disconnect = debug_get_bool_option_exit_on_disconnect(); 506 + s->exit_on_disconnect = exit_on_disconnect; 484 507 s->exit_when_idle = debug_get_bool_option_exit_when_idle(); 485 508 s->last_client_disconnect_ns = 0; 486 509 uint64_t delay_ms = debug_get_num_option_exit_when_idle_delay_ms(); ··· 489 512 xret = xrt_instance_create(NULL, &s->xinst); 490 513 IPC_CHK_WITH_GOTO(s, xret, "xrt_instance_create", error); 491 514 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); 515 + ret = ipc_server_mainloop_init(&s->ml, s->no_stdin); 500 516 if (ret < 0) { 501 517 xret = XRT_ERROR_IPC_MAINLOOP_FAILED_TO_INIT; 502 518 } ··· 599 615 ics->client_state.z_order = z_order; 600 616 601 617 if (ics->xc != NULL) { 602 - xrt_syscomp_set_state(ics->server->xsysc, ics->xc, visible, focused); 618 + xrt_syscomp_set_state(ics->server->xsysc, ics->xc, visible, focused, os_monotonic_get_ns()); 603 619 xrt_syscomp_set_z_order(ics->server->xsysc, ics->xc, z_order); 604 620 } 605 621 } ··· 771 787 return XRT_SUCCESS; 772 788 } 773 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 + 774 818 775 819 /* 776 820 * ··· 779 823 */ 780 824 781 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 782 866 ipc_server_get_client_app_state(struct ipc_server *s, uint32_t client_id, struct ipc_app_state *out_ias) 783 867 { 784 868 os_mutex_lock(&s->global_state.lock); ··· 937 1021 it->state = IPC_THREAD_STARTING; 938 1022 939 1023 // Allocate a new ID, avoid zero. 940 - //! @todo validate ID. 941 - uint32_t id = ++vs->id_generator; 1024 + uint32_t id = allocate_id_locked(vs); 942 1025 943 1026 // Reset everything. 944 1027 U_ZERO((struct ipc_client_state *)ics); 945 1028 946 1029 // Set state. 1030 + ics->local_space_overseer_index = UINT32_MAX; 947 1031 ics->client_state.id = id; 948 1032 ics->imc.ipc_handle = ipc_handle; 949 1033 ics->server = vs; ··· 955 1039 ics->plane_detection_ids = NULL; 956 1040 ics->plane_detection_xdev = NULL; 957 1041 958 - xrt_result_t xret = init_shm(vs, ics); 1042 + xrt_result_t xret = init_shm_and_instance_state(vs, ics); 959 1043 if (xret != XRT_SUCCESS) { 960 1044 961 1045 // Unlock when we are done. ··· 995 1079 // Allocate the server itself. 996 1080 struct ipc_server *s = U_TYPED_CALLOC(struct ipc_server); 997 1081 1082 + // Can be set by either. 1083 + s->no_stdin = ismi->no_stdin || debug_get_bool_option_no_stdin(); 1084 + 998 1085 #ifdef XRT_OS_WINDOWS 999 1086 timeBeginPeriod(1); 1000 1087 #endif ··· 1006 1093 */ 1007 1094 u_debug_gui_create(&ismi->udgci, &s->debug_gui); 1008 1095 1009 - xret = init_all(s, log_level); 1096 + xret = init_all(s, log_level, callbacks, data, ismi->exit_on_disconnect); 1010 1097 U_LOG_CHK_ONLY_PRINT(log_level, xret, "init_all"); 1011 1098 if (xret != XRT_SUCCESS) { 1012 - // Propegate the failure. 1099 + // Propagate the failure. 1013 1100 callbacks->init_failed(xret, data); 1014 1101 u_debug_gui_stop(&s->debug_gui); 1015 1102 free(s); 1016 1103 return -1; 1017 1104 } 1018 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 + 1019 1118 // Start the debug UI now (if enabled). 1020 1119 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 1120 1025 1121 // Main loop. 1026 1122 ret = main_loop(s); ··· 1044 1140 return ret; 1045 1141 } 1046 1142 1143 + int 1144 + ipc_server_stop(struct ipc_server *s) 1145 + { 1146 + s->running = false; 1147 + return 0; 1148 + } 1047 1149 1048 1150 #ifndef XRT_OS_ANDROID 1049 1151 ··· 1071 1173 // No-op 1072 1174 } 1073 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 + 1074 1188 int 1075 1189 ipc_server_main(int argc, char **argv, const struct ipc_server_main_info *ismi) 1076 1190 { ··· 1078 1192 .init_failed = init_failed, 1079 1193 .mainloop_entering = mainloop_entering, 1080 1194 .mainloop_leaving = mainloop_leaving, 1195 + .client_connected = client_connected, 1196 + .client_disconnected = client_disconnected, 1081 1197 }; 1082 1198 1083 1199 return ipc_server_main_common(ismi, &callbacks, NULL);
+7 -6
src/xrt/ipc/shared/ipc_protocol.h
··· 1 1 // Copyright 2020-2024 Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 31 32 32 33 33 34 #define IPC_CRED_SIZE 1 // auth not implemented 34 - #define IPC_BUF_SIZE 512 // must be >= largest message length in bytes 35 + #define IPC_BUF_SIZE 2048 // must be >= largest message length in bytes 35 36 #define IPC_MAX_VIEWS 8 // max views we will return configs for 36 37 #define IPC_MAX_FORMATS 32 // max formats our server-side compositor supports 37 38 #define IPC_MAX_DEVICES 8 // max number of devices we will map using shared mem 38 39 #define IPC_MAX_LAYERS XRT_MAX_LAYERS 39 40 #define IPC_MAX_SLOTS 128 40 - #define IPC_MAX_CLIENTS 8 41 + #define IPC_MAX_CLIENTS 32 41 42 #define IPC_MAX_RAW_VIEWS 32 // Max views that we can get, artificial limit. 42 43 #define IPC_EVENT_QUEUE_SIZE 32 43 44 ··· 84 85 { 85 86 enum xrt_device_name name; 86 87 88 + //! Offset into the array of pairs where this input bindings starts. 89 + uint32_t first_input_index; 87 90 //! Number of inputs. 88 91 uint32_t input_count; 89 - //! Offset into the array of pairs where this input bindings starts. 90 - uint32_t first_input_index; 91 92 92 - //! Number of outputs. 93 - uint32_t output_count; 94 93 //! Offset into the array of pairs where this output bindings starts. 95 94 uint32_t first_output_index; 95 + //! Number of outputs. 96 + uint32_t output_count; 96 97 }; 97 98 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 1 #!/usr/bin/env python3 2 2 # Copyright 2020-2023, Collabora, Ltd. 3 + # Copyright 2025, NVIDIA CORPORATION. 3 4 # SPDX-License-Identifier: BSL-1.0 4 5 """Generate code from a JSON file describing the IPC protocol.""" 5 6 6 7 import argparse 8 + import os.path 9 + from string import Template 7 10 8 11 from ipcproto.common import (Proto, write_decl, write_invocation, 9 12 write_result_handler, write_cpp_header_guard_start, ··· 136 139 137 140 Defines command enum, utility functions, and command and reply structures. 138 141 """ 139 - f = open(file, "w") 140 - f.write(header.format(brief='Generated IPC protocol header', suffix='')) 141 - f.write(''' 142 - #pragma once 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') 143 145 144 - #include "xrt/xrt_compiler.h" 146 + # Goes directly into the template file. 147 + ipc_commands = '\n'.join([f'\t{call.id},' for call in p.calls]) 145 148 146 - ''') 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]) 147 151 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 - 152 + # Build message and reply structs. 153 + ipc_msg_structs_list = [] 186 154 for call in p.calls: 187 155 # Should we emit a msg struct. 188 156 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') 157 + struct_lines = [f'struct ipc_{call.name}_msg'] 158 + struct_lines.append('{') 159 + struct_lines.append('\tenum ipc_command cmd;') 192 160 for arg in call.in_args: 193 - f.write('\t' + arg.get_struct_field() + ';\n') 161 + struct_lines.append('\t' + arg.get_struct_field() + ';') 194 162 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') 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 + 198 170 # Should we emit a reply struct. 199 171 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') 172 + struct_lines = [f'struct ipc_{call.name}_reply'] 173 + struct_lines.append('{') 174 + struct_lines.append('\txrt_result_t result;') 203 175 for arg in call.out_args: 204 - f.write('\t' + arg.get_struct_field() + ';\n') 205 - f.write('};\n') 176 + struct_lines.append('\t' + arg.get_struct_field() + ';') 177 + struct_lines.append('};') 206 178 207 - f.write('#pragma pack (pop)\n') 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) 208 186 209 - write_cpp_header_guard_end(f) 210 - f.close() 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) 211 201 212 202 213 203 def generate_client_c(file, p): ··· 530 520 generate_server_c(output, p) 531 521 if output.endswith("ipc_server_generated.h"): 532 522 generate_server_header(output, p) 533 - if output.endswith("structs.txt"): 523 + if output.endswith("structs.txt") or output.endswith("ipc-structs.txt"): 534 524 generate_struct_names(output, p) 535 525 536 526
+10 -1
src/xrt/state_trackers/gui/gui_scene_debug.c
··· 521 521 igPopItemFlag(); 522 522 igPopStyleVar(1); 523 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 + } 524 532 } 525 533 526 534 static void ··· 689 697 case U_VAR_KIND_POSE: on_pose(name, ptr); break; 690 698 case U_VAR_KIND_LOG_LEVEL: igCombo_Str(name, (int *)ptr, "Trace\0Debug\0Info\0Warn\0Error\0\0", 5); break; 691 699 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; 700 + case U_VAR_KIND_RO_RAW_TEXT: igText("%s", (char *)ptr); break; 693 701 case U_VAR_KIND_RO_I16: igInputScalar(name, ImGuiDataType_S16, ptr, NULL, NULL, NULL, ro_i_flags); break; 694 702 case U_VAR_KIND_RO_I32: igInputScalar(name, ImGuiDataType_S32, ptr, NULL, NULL, NULL, ro_i_flags); break; 695 703 case U_VAR_KIND_RO_U16: igInputScalar(name, ImGuiDataType_U16, ptr, NULL, NULL, NULL, ro_i_flags); break; ··· 706 714 case U_VAR_KIND_GUI_HEADER: assert(false && "Should be handled before this"); break; 707 715 case U_VAR_KIND_GUI_HEADER_BEGIN: on_gui_header_begin(name, state); break; 708 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; 709 718 case U_VAR_KIND_SINK_DEBUG: on_sink_debug_var(name, ptr, state); break; 710 719 case U_VAR_KIND_NATIVE_IMAGES_DEBUG: on_native_images_debug_var(name, ptr, state); break; 711 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 413 igBegin("Remote control", NULL, 0); 414 414 415 415 #ifdef XRT_BUILD_DRIVER_REMOTE 416 - if (gr->rc.fd < 0) { 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) { 417 422 on_not_connected(gr, p); 418 423 } else { 419 424 on_connected(gr, p); ··· 451 456 452 457 gr->base.render = scene_render; 453 458 gr->base.destroy = scene_destroy; 459 + #ifdef XRT_OS_WINDOWS 460 + gr->rc.fd = INVALID_SOCKET; 461 + #else 454 462 gr->rc.fd = -1; 463 + #endif 455 464 456 465 // GUI input defaults. 457 466 if (address != NULL) {
+2 -2
src/xrt/state_trackers/gui/gui_scene_tracking_overrides.c
··· 11 11 #include "util/u_misc.h" 12 12 #include "util/u_format.h" 13 13 #include "util/u_logging.h" 14 + #include "util/u_pretty_print.h" 14 15 15 16 #include "util/u_config_json.h" 16 17 ··· 23 24 #include "gui_common.h" 24 25 #include "gui_imgui.h" 25 26 26 - #include "bindings/b_generated_bindings_helpers.h" 27 27 28 28 struct gui_tracking_overrides 29 29 { ··· 243 243 continue; 244 244 } 245 245 246 - const char *name_str = xrt_input_name_string(input_name); 246 + const char *name_str = u_str_xrt_input_name(input_name); 247 247 bool selected = o->input_name == input_name; 248 248 if (igCheckbox(name_str, &selected)) { 249 249 o->input_name = input_name;
+5 -1
src/xrt/state_trackers/oxr/CMakeLists.txt
··· 106 106 target_sources(st_oxr PRIVATE oxr_api_body_tracking.c oxr_body_tracking.c) 107 107 endif() 108 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 + 109 113 if(XRT_FEATURE_OPENXR_FACIAL_TRACKING_HTC) 110 - target_sources(st_oxr PRIVATE oxr_api_face_tracking.c oxr_face_tracking.c) 114 + target_sources(st_oxr PRIVATE oxr_api_face_tracking_htc.c oxr_face_tracking_htc.c) 111 115 endif() 112 116 113 117 if(XRT_FEATURE_OPENXR_FACE_TRACKING2_FB)
+7 -7
src/xrt/state_trackers/oxr/oxr_api_action.c
··· 1 1 // Copyright 2019-2023, Collabora, Ltd. 2 - // Copyright 2023, NVIDIA CORPORATION. 2 + // Copyright 2023-2025, NVIDIA CORPORATION. 3 3 // SPDX-License-Identifier: BSL-1.0 4 4 /*! 5 5 * @file ··· 156 156 os_mutex_unlock(&sess->sys->sync_actions_mutex); 157 157 } 158 158 159 - if (syncInfo->countActiveActionSets == 0) { 160 - // nothing to do 161 - return XR_SUCCESS; 162 - } 163 - 164 159 for (uint32_t i = 0; i < syncInfo->countActiveActionSets; i++) { 165 160 struct oxr_action_set *act_set = NULL; 161 + 166 162 OXR_VERIFY_ACTIONSET_NOT_NULL(&log, syncInfo->activeActionSets[i].actionSet, act_set); 167 163 168 164 XrResult res = oxr_verify_subaction_path_sync(&log, sess->sys->inst, act_set, ··· 238 234 path_verify_fn_t dpad_path_fn = NULL; 239 235 path_verify_fn_t dpad_emulator_fn = NULL; 240 236 ext_verify_fn_t ext_verify_fn = NULL; 241 - bool has_dpad = inst->extensions.EXT_dpad_binding; 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 242 243 243 struct profile_template *interaction_profile_template = NULL; 244 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 779 oxr_xrCancelFutureEXT(XrInstance instance, const XrFutureCancelInfoEXT *cancelInfo); 780 780 #endif 781 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 + 782 806 /*! 783 807 * @} 784 808 */
+50 -10
src/xrt/state_trackers/oxr/oxr_api_instance.c
··· 1 1 // Copyright 2018-2019, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 256 257 struct oxr_logger log; 257 258 OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst, "xrResultToString"); 258 259 259 - #define MAKE_RESULT_CASE(VAL, _) \ 260 - case VAL: snprintf(buffer, XR_MAX_RESULT_STRING_SIZE, #VAL); break; 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 261 264 262 265 switch (value) { 263 266 XR_LIST_ENUM_XrResult(MAKE_RESULT_CASE); 264 267 default: 265 - snprintf(buffer, XR_MAX_RESULT_STRING_SIZE, "XR_UNKNOWN_%s_%d", value < 0 ? "FAILURE" : "SUCCESS", 266 - value); 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 + } 267 273 } 274 + 268 275 // The function snprintf always null terminates. 276 + #undef MAKE_RESULT_CASE 277 + #undef EXT_RESULT 269 278 270 279 return XR_SUCCESS; 271 280 } ··· 282 291 static_assert(XR_MAX_STRUCTURE_NAME_SIZE == 64, 283 292 "XR_MAX_STRUCTURE_NAME_SIZE has changed, please update the format string"); 284 293 285 - #define MAKE_TYPE_CASE(VAL, _) \ 286 - case VAL: snprintf(buffer, XR_MAX_STRUCTURE_NAME_SIZE, "%.63s", #VAL); break; 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 287 298 288 299 switch (value) { 289 300 XR_LIST_ENUM_XrStructureType(MAKE_TYPE_CASE); 290 - default: snprintf(buffer, XR_MAX_STRUCTURE_NAME_SIZE, "XR_UNKNOWN_STRUCTURE_TYPE_%d", value); 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 + } 291 312 } 313 + 292 314 // The function snprintf always null terminates. 293 315 #undef MAKE_TYPE_CASE 316 + #undef EXT_TYPE 317 + 294 318 return XR_SUCCESS; 295 319 } 296 320 ··· 311 335 static_assert(XR_MAX_STRUCTURE_NAME_SIZE_EXTENDED_KHR == 256, 312 336 "XR_MAX_STRUCTURE_NAME_SIZE_EXTENDED_KHR has changed, please update the format string"); 313 337 314 - #define MAKE_TYPE_CASE(VAL, _) \ 315 - case VAL: snprintf(buffer, XR_MAX_STRUCTURE_NAME_SIZE_EXTENDED_KHR, "%.255s", #VAL); break; 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 316 342 317 343 switch (value) { 318 344 XR_LIST_ENUM_XrStructureType(MAKE_TYPE_CASE); 319 - default: snprintf(buffer, XR_MAX_STRUCTURE_NAME_SIZE_EXTENDED_KHR, "XR_UNKNOWN_STRUCTURE_TYPE_%d", value); 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 + } 320 357 } 358 + 321 359 // The function snprintf always null terminates. 322 360 #undef MAKE_TYPE_CASE 361 + #undef EXT_TYPE 362 + 323 363 return XR_SUCCESS; 324 364 } 325 365 #endif // OXR_HAVE_KHR_extended_struct_name_lengths
+7
src/xrt/state_trackers/oxr/oxr_api_negotiate.c
··· 419 419 ENTRY_IF_EXT(xrCancelFutureEXT, EXT_future); 420 420 #endif // OXR_HAVE_EXT_future 421 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 + 422 429 #ifdef OXR_HAVE_KHR_extended_struct_name_lengths 423 430 ENTRY_IF_EXT(xrStructureTypeToString2KHR, KHR_extended_struct_name_lengths); 424 431 #endif // OXR_HAVE_KHR_extended_struct_name_lengths
+11 -12
src/xrt/state_trackers/oxr/oxr_api_session.c
··· 1 1 // Copyright 2019-2024, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 99 100 // in a headless session there is no compositor and primaryViewConfigurationType must be ignored 100 101 if (sess->compositor != NULL) { 101 102 OXR_VERIFY_VIEW_CONFIG_TYPE(&log, sess->sys->inst, beginInfo->primaryViewConfigurationType); 103 + OXR_VERIFY_VIEW_CONFIG_TYPE_SUPPORTED(&log, sess->sys, beginInfo->primaryViewConfigurationType); 102 104 } 103 105 104 106 // Going to effectively double check this, but this gives us an early out. ··· 239 241 OXR_VERIFY_SPACE_NOT_NULL(&log, viewLocateInfo->space, spc); 240 242 OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, viewState, XR_TYPE_VIEW_STATE); 241 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 + } 242 252 243 253 if (viewCapacityInput == 0) { 244 254 OXR_VERIFY_ARG_NOT_NULL(&log, viewCountOutput); ··· 255 265 viewLocateInfo->displayTime); 256 266 } 257 267 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 268 return oxr_session_locate_views( // 266 269 &log, // 267 270 sess, // ··· 300 303 visibilityMask->indexCountOutput = 0; 301 304 302 305 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 - } 306 + OXR_VERIFY_VIEW_CONFIG_TYPE_SUPPORTED(&log, sess->sys, viewConfigurationType); 308 307 309 308 OXR_VERIFY_VIEW_INDEX(&log, viewIndex); 310 309
+46 -3
src/xrt/state_trackers/oxr/oxr_api_swapchain.c
··· 1 1 // Copyright 2019-2020, Collabora, Ltd. 2 + // Copyright 2024-2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 82 83 83 84 // Short hand. 84 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 + */ 85 93 86 94 XrSwapchainUsageFlags flags = 0; 87 95 flags |= XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT; ··· 102 110 "(createInfo->usageFlags == 0x%04" PRIx64 ") contains invalid flags", 103 111 createInfo->usageFlags); 104 112 } 113 + 114 + 115 + /* 116 + * Format. 117 + */ 118 + 105 119 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) { 120 + for (uint32_t i = 0; i < xc_info->format_count; i++) { 121 + if (xc_info->formats[i] == createInfo->format) { 109 122 format_supported = true; 110 123 break; 111 124 } ··· 115 128 return oxr_error(&log, XR_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED, 116 129 "(createInfo->format == 0x%04" PRIx64 ") is not supported", createInfo->format); 117 130 } 131 + 132 + 133 + /* 134 + * Format list. 135 + */ 118 136 119 137 #ifdef OXR_HAVE_KHR_vulkan_swapchain_format_list 120 138 const XrVulkanSwapchainFormatListCreateInfoKHR *format_list = NULL; ··· 136 154 } 137 155 } 138 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 + */ 139 182 140 183 ret = sess->create_swapchain(&log, sess, createInfo, &sc); 141 184 if (ret != XR_SUCCESS) {
+26 -10
src/xrt/state_trackers/oxr/oxr_api_system.c
··· 1 1 // Copyright 2018-2020, Collabora, Ltd. 2 + // Copyright 2024-2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 64 65 struct oxr_system *systems[1] = {&inst->system}; 65 66 uint32_t system_count = ARRAY_SIZE(systems); 66 67 67 - XrResult ret = oxr_system_select(&log, systems, system_count, getInfo->formFactor, &selected); 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 + 68 76 if (ret != XR_SUCCESS) { 69 - return ret; 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 70 83 } 71 84 72 85 *systemId = selected->systemId; ··· 121 134 OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst, "xrEnumerateEnvironmentBlendModes"); 122 135 OXR_VERIFY_SYSTEM_AND_GET(&log, inst, systemId, sys); 123 136 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 - } 137 + OXR_VERIFY_VIEW_CONFIG_TYPE_SUPPORTED(&log, sys, viewConfigurationType); 131 138 132 139 return oxr_system_enumerate_blend_modes(&log, sys, viewConfigurationType, environmentBlendModeCapacityInput, 133 140 environmentBlendModeCountOutput, environmentBlendModes); ··· 146 153 OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst, "xrGetViewConfigurationProperties"); 147 154 OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, configurationProperties, XR_TYPE_VIEW_CONFIGURATION_PROPERTIES); 148 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); 149 158 150 159 return oxr_system_get_view_conf_properties(&log, sys, viewConfigurationType, configurationProperties); 151 160 } ··· 164 173 struct oxr_logger log; 165 174 OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst, "xrEnumerateViewConfigurationViews"); 166 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); 167 178 168 179 for (uint32_t i = 0; i < viewCapacityInput; i++) { 169 180 OXR_VERIFY_ARG_ARRAY_ELEMENT_TYPE(&log, views, i, XR_TYPE_VIEW_CONFIGURATION_VIEW); ··· 328 339 329 340 OXR_VERIFY_SYSTEM_AND_GET(&log, inst, getInfo->systemId, sys); 330 341 OXR_VERIFY_ARG_NOT_NULL(&log, vkPhysicalDevice); 342 + OXR_VERIFY_ARG_NOT_NULL(&log, sys->vk_get_instance_proc_addr); 331 343 OXR_VERIFY_XSYSC(&log, sys); 332 344 333 - return oxr_vk_get_physical_device(&log, inst, sys, getInfo->vulkanInstance, vkGetInstanceProcAddr, 345 + return oxr_vk_get_physical_device(&log, inst, sys, getInfo->vulkanInstance, sys->vk_get_instance_proc_addr, 334 346 vkPhysicalDevice); 335 347 } 336 348 ··· 393 405 394 406 // createInfo->vulkanAllocator can be NULL 395 407 408 + sys->vk_get_instance_proc_addr = createInfo->pfnGetInstanceProcAddr; 409 + 396 410 if (createInfo->vulkanCreateInfo->sType != VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO) { 397 411 return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE, 398 412 "createInfo->vulkanCreateInfo->sType must be " ··· 428 442 OXR_VERIFY_ARG_NOT_NULL(&log, sys->suggested_vulkan_physical_device); 429 443 OXR_VERIFY_ARG_NOT_NULL(&log, sys->vulkan_enable2_instance); 430 444 OXR_VERIFY_XSYSC(&log, sys); 445 + 446 + sys->vk_get_instance_proc_addr = createInfo->pfnGetInstanceProcAddr; 431 447 432 448 if (sys->suggested_vulkan_physical_device != createInfo->vulkanPhysicalDevice) { 433 449 return oxr_error(&log, XR_ERROR_HANDLE_INVALID,
+56 -11
src/xrt/state_trackers/oxr/oxr_api_verify.h
··· 1 1 // Copyright 2018-2024, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 22 23 struct oxr_action_set; 23 24 struct oxr_extension_status; 24 25 struct oxr_instance; 26 + struct oxr_system; 25 27 struct oxr_logger; 26 28 struct oxr_subaction_paths; 27 29 ··· 95 97 #define OXR_VERIFY_FUTURE_AND_INIT_LOG(log, thing, new_thing, name) \ 96 98 OXR_VERIFY_AND_SET_AND_INIT(log, thing, new_thing, oxr_future_ext, FUTURE, name, new_thing->inst); \ 97 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) 98 102 // clang-format on 99 103 100 104 #define OXR_VERIFY_INSTANCE_NOT_NULL(log, arg, new_arg) OXR_VERIFY_SET(log, arg, new_arg, oxr_instance, INSTANCE); ··· 200 204 } \ 201 205 } while (false) 202 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 + 203 226 #define OXR_VERIFY_SUBACTION_PATHS(log, count, paths) \ 204 227 do { \ 205 228 if (count > 0 && paths == NULL) { \ ··· 232 255 \ 233 256 if (!math_vec3_validate((struct xrt_vec3 *)&p.position)) { \ 234 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); \ 235 269 } \ 236 270 } while (false) 237 271 ··· 243 277 } \ 244 278 } while (false) 245 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 + 246 288 #define OXR_VERIFY_VIEW_INDEX(log, index) \ 247 289 do { \ 248 290 if (index > 2) { \ ··· 308 350 } \ 309 351 } while (false) 310 352 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 353 #define OXR_VERIFY_HAND_TRACKING_DATA_SOURCE_OR_NULL(log, data_source_info) \ 323 354 do { \ 324 355 if (data_source_info != NULL) { \ ··· 333 364 do { \ 334 365 if (OXR_FT->xft == NULL) { \ 335 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); \ 336 375 } \ 337 376 } while (false) 338 377 ··· 408 447 struct oxr_instance *inst, 409 448 XrViewConfigurationType view_conf, 410 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); 411 456 412 457 XrResult 413 458 oxr_verify_XrSessionCreateInfo(struct oxr_logger * /*log*/,
+23 -2
src/xrt/state_trackers/oxr/oxr_binding.c
··· 1 1 // Copyright 2018-2020,2023 Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 462 463 if (name == XRT_DEVICE_INVALID) { 463 464 return false; 464 465 } 466 + 465 467 /* 466 468 * 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. 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. 468 482 */ 469 483 for (uint32_t i = 0; i < ARRAY_SIZE(profile_templates); i++) { 470 484 if (name == profile_templates[i].name) { 471 - if (interaction_profile_find_in_session(log, sess, profile_templates[i].path_cache, out_p)) { 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) { 472 493 return true; 473 494 } 474 495 }
+77
src/xrt/state_trackers/oxr/oxr_conversions.h
··· 16 16 #include "xrt/xrt_vulkan_includes.h" 17 17 #include "xrt/xrt_openxr_includes.h" 18 18 19 + #include "oxr_defines.h" 20 + 19 21 20 22 /* 21 23 * ··· 289 291 default: assert(false); return XR_HAND_TRACKING_DATA_SOURCE_MAX_ENUM_EXT; 290 292 } 291 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 15 16 16 // For corruption and layer checking. 17 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") 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 32 // body tracker 33 - #define OXR_XR_DEBUG_BTRACKER (*(uint64_t *)"oxrbtra\0") 34 - #define OXR_XR_DEBUG_XDEVLIST (*(uint64_t *)"oxrxdli\0") 33 + #define OXR_XR_DEBUG_BTRACKER (*(uint64_t *)"oxrbtra\0") 34 + #define OXR_XR_DEBUG_XDEVLIST (*(uint64_t *)"oxrxdli\0") 35 35 // plane detection 36 - #define OXR_XR_DEBUG_PLANEDET (*(uint64_t *)"oxrplan\0") 36 + #define OXR_XR_DEBUG_PLANEDET (*(uint64_t *)"oxrplan\0") 37 37 // futures 38 - #define OXR_XR_DEBUG_FUTURE (*(uint64_t *)"oxrfutr\0") 38 + #define OXR_XR_DEBUG_FUTURE (*(uint64_t *)"oxrfutr\0") 39 39 // clang-format on 40 40 41 41 /*!
+24 -12
src/xrt/state_trackers/oxr/oxr_extension_support.h
··· 475 475 476 476 477 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 + /* 478 489 * XR_BD_controller_interaction 479 490 */ 480 491 #if defined(XR_BD_controller_interaction) && defined(XRT_FEATURE_OPENXR_INTERACTION_BYTEDANCE) ··· 797 808 798 809 799 810 /* 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 811 * XR_MNDX_egl_enable 812 812 */ 813 813 #if defined(XR_MNDX_egl_enable) && defined(XR_USE_PLATFORM_EGL) ··· 837 837 #define OXR_EXTENSION_SUPPORT_MNDX_hydra(_) _(MNDX_hydra, MNDX_HYDRA) 838 838 #else 839 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(_) 840 851 #endif 841 852 842 853 ··· 936 947 OXR_EXTENSION_SUPPORT_EXT_plane_detection(_) \ 937 948 OXR_EXTENSION_SUPPORT_EXT_samsung_odyssey_controller(_) \ 938 949 OXR_EXTENSION_SUPPORT_EXT_user_presence(_) \ 950 + OXR_EXTENSION_SUPPORT_ANDROID_face_tracking(_) \ 939 951 OXR_EXTENSION_SUPPORT_BD_controller_interaction(_) \ 940 952 OXR_EXTENSION_SUPPORT_FB_body_tracking(_) \ 941 953 OXR_EXTENSION_SUPPORT_FB_composition_layer_alpha_blend(_) \ ··· 964 976 OXR_EXTENSION_SUPPORT_HTCX_vive_tracker_interaction(_) \ 965 977 OXR_EXTENSION_SUPPORT_MNDX_ball_on_a_stick_controller(_) \ 966 978 OXR_EXTENSION_SUPPORT_MNDX_blubur_s1(_) \ 967 - OXR_EXTENSION_SUPPORT_MNDX_oculus_remote(_) \ 968 979 OXR_EXTENSION_SUPPORT_MNDX_egl_enable(_) \ 969 980 OXR_EXTENSION_SUPPORT_MNDX_force_feedback_curl(_) \ 970 981 OXR_EXTENSION_SUPPORT_MNDX_hydra(_) \ 982 + OXR_EXTENSION_SUPPORT_MNDX_oculus_remote(_) \ 971 983 OXR_EXTENSION_SUPPORT_MNDX_psvr2_interaction(_) \ 972 984 OXR_EXTENSION_SUPPORT_MNDX_system_buttons(_) \ 973 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 1 // Copyright 2018-2024, Collabora, Ltd. 2 - // Copyright 2023, NVIDIA CORPORATION. 2 + // Copyright 2023-2025, NVIDIA CORPORATION. 3 3 // SPDX-License-Identifier: BSL-1.0 4 4 /*! 5 5 * @file ··· 9 9 * @ingroup oxr_main 10 10 */ 11 11 12 - #include "b_generated_bindings_helpers.h" 13 12 #include "oxr_bindings/b_oxr_generated_bindings.h" 14 13 #include "util/u_debug.h" 15 14 #include "util/u_time.h" ··· 515 514 */ 516 515 517 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 518 557 do_inputs(struct oxr_binding *binding_point, 519 558 struct xrt_device *xdev, 520 559 struct xrt_binding_profile *xbp, ··· 523 562 uint32_t *input_count) 524 563 { 525 564 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 - } 565 + enum xrt_input_name dpad_activate_name = 0; 533 566 534 - // We have found a device mapping. 535 - name = xbp->inputs[i].device; 536 - break; 537 - } 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); 538 570 539 - // Didn't find a mapping. 540 - if (name == 0) { 571 + // We couldn't find the needed inputs on the device. 572 + if (!t1 || !t2) { 541 573 return false; 542 574 } 575 + } else { 576 + name = binding_point->input; 577 + dpad_activate_name = binding_point->dpad_activate; 543 578 } 544 579 545 580 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; 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; 558 592 } 559 - return true; 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; 560 602 } 561 603 562 - return false; 604 + return true; 563 605 } 564 606 565 607 static bool ··· 771 813 if (found) { 772 814 if (xbp == NULL) { 773 815 oxr_slog(slog, "\t\t\t\tBound (xdev '%s'): %s!\n", xdev->str, 774 - xrt_input_name_string(binding_points[i]->input)); 816 + u_str_xrt_input_name(binding_points[i]->input)); 775 817 } else { 776 818 oxr_slog(slog, "\t\t\t\tBound (xbp)!\n"); 777 819 } ··· 1626 1668 // Only add the input if we can find a transform. 1627 1669 1628 1670 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, 1671 + u_str_xrt_input_name(inputs[i].input->name), act_ref->name, 1630 1672 xr_action_type_to_str(act_ref->action_type)); 1631 1673 1632 1674 enum oxr_dpad_region dpad_region; ··· 1667 1709 struct xrt_input *input = cache->inputs[i].input; 1668 1710 enum xrt_input_type t = XRT_GET_INPUT_TYPE(input->name); 1669 1711 bool active = input->active; 1670 - oxr_slog(slog, "\t\t\t'%s' ('%s') on '%s' (%s)\n", xrt_input_name_string(input->name), 1712 + oxr_slog(slog, "\t\t\t'%s' ('%s') on '%s' (%s)\n", u_str_xrt_input_name(input->name), 1671 1713 xrt_input_type_to_str(t), cache->inputs[i].xdev->str, 1672 1714 active ? "active" : "inactive"); 1673 1715 } ··· 1862 1904 struct oxr_action_set *act_set = NULL; 1863 1905 struct oxr_action_set_attachment *act_set_attached = NULL; 1864 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 + 1865 1912 // Check that all action sets has been attached. 1866 1913 for (uint32_t i = 0; i < countActionSets; i++) { 1867 1914 oxr_session_get_action_set_attachment(sess, actionSets[i].actionSet, &act_set_attached, &act_set); ··· 1871 1918 "not been attached to this session", 1872 1919 i, act_set != NULL ? act_set->data->name : "NULL"); 1873 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; 1874 1939 } 1875 1940 1876 1941 // Synchronize outputs to this time. ··· 1922 1987 OXR_FOR_EACH_SUBACTION_PATH(ACCUMULATE_REQUESTED) 1923 1988 #undef ACCUMULATE_REQUESTED 1924 1989 } 1990 + 1991 + //! @TODO This validation is not allowed here, must done above. 1925 1992 if (!any_action_with_subactionpath) { 1926 1993 return oxr_error(log, XR_ERROR_PATH_UNSUPPORTED, 1927 1994 "No action with specified subactionpath in actionset");
+96 -54
src/xrt/state_trackers/oxr/oxr_instance.c
··· 91 91 inst->system.visibility_mask[i] = NULL; 92 92 } 93 93 94 + os_mutex_destroy(&inst->system_init_lock); 95 + 94 96 xrt_space_overseer_destroy(&inst->system.xso); 95 97 os_mutex_destroy(&inst->system.sync_actions_mutex); 96 98 xrt_system_devices_destroy(&inst->system.xsysd); ··· 199 201 { 200 202 // Reset. 201 203 inst->quirks.skip_end_session = false; 204 + inst->quirks.disable_vulkan_format_depth = false; 202 205 inst->quirks.disable_vulkan_format_depth_stencil = false; 203 206 inst->quirks.no_validation_error_in_create_ref_space = false; 204 207 ··· 256 259 ret = oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to init sync action mutex"); 257 260 return ret; 258 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 + 259 269 260 270 #ifdef XRT_FEATURE_CLIENT_DEBUG_GUI 261 271 struct u_debug_gui_create_info udgci = { ··· 331 341 #ifdef OXR_HAVE_META_body_tracking_calibration 332 342 .meta_body_tracking_calibration_enabled = extensions->META_body_tracking_calibration, 333 343 #endif 344 + #ifdef OXR_HAVE_ANDROID_face_tracking 345 + .android_face_tracking_enabled = extensions->ANDROID_face_tracking, 346 + #endif 334 347 }; 335 348 snprintf(i_info.app_info.application_name, sizeof(i_info.app_info.application_name), "%s", 336 349 createInfo->applicationInfo.applicationName); ··· 370 383 } 371 384 #endif // XRT_OS_ANDROID 372 385 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 386 inst->timekeeping = time_state_create(inst->xinst->startup_timestamp); 421 387 422 388 //! @todo check if this (and other creates) failed? ··· 429 395 430 396 u_var_add_root((void *)inst, "XrInstance", true); 431 397 432 - #ifdef XRT_FEATURE_CLIENT_DEBUG_GUI 433 - u_debug_gui_start(inst->debug_ui, inst->xinst, sys->xsysd); 434 - #endif 435 - 436 398 oxr_log(log, 437 399 "Instance created\n" 438 400 "\tcreateInfo->applicationInfo.applicationName: %s\n" ··· 442 404 "\tcreateInfo->applicationInfo.apiVersion: %d.%d.%d\n" 443 405 "\tappinfo.detected.engine.name: %s\n" 444 406 "\tappinfo.detected.engine.version: %i.%i.%i\n" 407 + "\tquirks.disable_vulkan_format_depth: %s\n" 445 408 "\tquirks.disable_vulkan_format_depth_stencil: %s\n" 446 409 "\tquirks.no_validation_error_in_create_ref_space: %s\n" 447 410 "\tquirks.skip_end_session: %s\n" ··· 457 420 inst->appinfo.detected.engine.major, // 458 421 inst->appinfo.detected.engine.minor, // 459 422 inst->appinfo.detected.engine.patch, // 423 + inst->quirks.disable_vulkan_format_depth ? "true" : "false", // 460 424 inst->quirks.disable_vulkan_format_depth_stencil ? "true" : "false", // 461 425 inst->quirks.no_validation_error_in_create_ref_space ? "true" : "false", // 462 426 inst->quirks.skip_end_session ? "true" : "false", // 463 427 inst->quirks.parallel_views ? "true" : "false" // 464 428 ); // 465 429 466 - debug_print_devices(log, sys); 467 - 468 - 469 430 #ifdef XRT_FEATURE_RENDERDOC 470 431 471 432 #ifdef __GNUC__ ··· 506 467 #endif 507 468 508 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); 509 551 510 552 return XR_SUCCESS; 511 553 }
+134 -6
src/xrt/state_trackers/oxr/oxr_objects.h
··· 1 1 // Copyright 2018-2024, Collabora, Ltd. 2 - // Copyright 2023, NVIDIA CORPORATION. 2 + // Copyright 2023-2025, NVIDIA CORPORATION. 3 3 // SPDX-License-Identifier: BSL-1.0 4 4 /*! 5 5 * @file ··· 127 127 struct oxr_action_set_ref; 128 128 struct oxr_action_ref; 129 129 struct oxr_hand_tracker; 130 + struct oxr_face_tracker_android; 130 131 struct oxr_facial_tracker_htc; 131 132 struct oxr_face_tracker2_fb; 132 133 struct oxr_body_tracker_fb; ··· 252 253 struct oxr_instance **out_inst); 253 254 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 + /*! 255 264 * @public @memberof oxr_instance 256 265 */ 257 266 XrResult ··· 459 468 return XRT_CAST_PTR_TO_OXR_HANDLE(XrFaceTracker2FB, face_tracker2_fb); 460 469 } 461 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 + 462 485 /*! 463 486 * 464 487 * @name oxr_input.c ··· 976 999 XrTime time, 977 1000 struct xrt_space_relation *out_relation); 978 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 + 979 1015 980 1016 /* 981 1017 * ··· 1086 1122 1087 1123 bool 1088 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); 1089 1128 1090 1129 void 1091 1130 oxr_system_get_face_tracking_htc_support(struct oxr_logger *log, ··· 1474 1513 }; 1475 1514 1476 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 + /*! 1477 1532 * Single or multiple devices grouped together to form a system that sessions 1478 1533 * can be created from. Might need to open devices to get all 1479 1534 * properties from it, but shouldn't. ··· 1505 1560 //! Have the client application called the gfx api requirements func? 1506 1561 bool gotten_requirements; 1507 1562 1508 - XrViewConfigurationType view_config_type; 1509 - XrViewConfigurationView views[2]; 1510 - uint32_t blend_mode_count; 1511 - XrEnvironmentBlendMode blend_modes[3]; 1563 + uint32_t view_config_count; 1564 + struct oxr_view_config_properties view_configs[XRT_MAX_COMPOSITOR_VIEW_CONFIGS_COUNT]; 1512 1565 1513 1566 XrReferenceSpaceType reference_spaces[5]; 1514 1567 uint32_t reference_space_count; ··· 1529 1582 //! The device returned with the last xrGetVulkanGraphicsDeviceKHR or xrGetVulkanGraphicsDevice2KHR call. 1530 1583 //! XR_NULL_HANDLE if neither has been called. 1531 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; 1532 1591 1533 1592 struct 1534 1593 { ··· 1689 1748 XrVersion major_minor; 1690 1749 } openxr_version; 1691 1750 1751 + // Protects the function oxr_instance_init_system_locked. 1752 + struct os_mutex system_init_lock; 1753 + 1692 1754 // Hardcoded single system. 1693 1755 struct oxr_system system; 1694 1756 ··· 1748 1810 1749 1811 struct 1750 1812 { 1751 - //! Unreal has a bug in the VulkanRHI backend. 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 + */ 1752 1832 bool disable_vulkan_format_depth_stencil; 1833 + 1753 1834 //! Unreal 4 has a bug calling xrEndSession; the function should just exit 1754 1835 bool skip_end_session; 1755 1836 ··· 1811 1892 struct oxr_session *next; 1812 1893 1813 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; 1814 1902 1815 1903 /*! 1816 1904 * There is a extra state between xrBeginSession has been called and ··· 3023 3111 XrResult 3024 3112 oxr_event_push_XrEventDataUserPresenceChangedEXT(struct oxr_logger *log, struct oxr_session *sess, bool isUserPresent); 3025 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 3026 3154 3027 3155 /*! 3028 3156 * @}
+203 -80
src/xrt/state_trackers/oxr/oxr_session.c
··· 1 1 // Copyright 2018-2024, Collabora, Ltd. 2 + // Copyright 2024-2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 65 66 */ 66 67 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 68 103 should_render(XrSessionState state) 69 104 { 70 105 switch (state) { ··· 127 162 if (inst->quirks.map_stage_to_local_floor) { 128 163 /* When stage is mapped to local_floor: 129 164 * ignore stage changes 130 - * for local_floor changes, send a duplicate envent for stage 165 + * for local_floor changes, send a duplicate event for stage 131 166 * */ 132 167 switch (ref_change->ref_type) { 133 168 case XRT_SPACE_REFERENCE_TYPE_STAGE: return XR_SUCCESS; ··· 224 259 for (uint32_t i = 0; i < xc->info.format_count; i++) { 225 260 int64_t format = xc->info.formats[i]; 226 261 227 - if (inst->quirks.disable_vulkan_format_depth_stencil && 228 - format == 130 /* VK_FORMAT_D32_SFLOAT_S8_UINT */) { 262 + if (should_skip_format(inst, sess, format)) { 229 263 continue; 230 264 } 231 265 ··· 249 283 250 284 struct xrt_compositor *xc = sess->compositor; 251 285 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 286 const struct oxr_extension_status *extensions = &sess->sys->inst->extensions; 265 287 266 288 const struct xrt_begin_session_info begin_session_info = { ··· 295 317 #ifdef OXR_HAVE_META_body_tracking_calibration 296 318 .meta_body_tracking_calibration_enabled = extensions->META_body_tracking_calibration, 297 319 #endif 320 + #ifdef OXR_HAVE_ANDROID_face_tracking 321 + .android_face_tracking_enabled = extensions->ANDROID_face_tracking, 322 + #endif 298 323 }; 299 324 300 325 xrt_result_t xret = xrt_comp_begin_session(xc, &begin_session_info); ··· 313 338 // Headless, pretend we got event from the compositor. 314 339 sess->compositor_visible = true; 315 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 + } 316 349 317 350 // 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); 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); 321 354 } 322 355 XrResult ret = oxr_frame_sync_begin_session(&sess->frame_sync); 323 356 if (ret != XR_SUCCESS) { ··· 325 358 "Frame sync object refused to let us begin session, probably already running"); 326 359 } 327 360 361 + // Set the current view configuration type, used in xrEndFrame. 362 + sess->current_view_config_type = beginInfo->primaryViewConfigurationType; 363 + 328 364 return oxr_session_success_result(sess); 329 365 } 330 366 ··· 372 408 sess->compositor_focused = false; 373 409 } 374 410 375 - oxr_session_change_state(log, sess, XR_SESSION_STATE_IDLE, 0); 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); 376 419 if (sess->exiting) { 377 - oxr_session_change_state(log, sess, XR_SESSION_STATE_EXITING, 0); 420 + oxr_session_change_state(log, sess, XR_SESSION_STATE_EXITING, now_xr); 378 421 } else { 379 422 #ifndef XRT_OS_ANDROID 380 423 // @todo In multi-clients scenario with a session being reused, changing session ··· 391 434 } 392 435 sess->has_ended_once = false; 393 436 437 + // Unset the current view configuration type here. 438 + sess->current_view_config_type = XR_VIEW_CONFIGURATION_TYPE_MAX_ENUM; 439 + 394 440 return oxr_session_success_result(sess); 395 441 } 396 442 397 443 XrResult 398 444 oxr_session_request_exit(struct oxr_logger *log, struct oxr_session *sess) 399 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 + 400 453 if (sess->state == XR_SESSION_STATE_FOCUSED) { 401 - oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, 0); 454 + oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, now_xr); 402 455 } 403 456 if (sess->state == XR_SESSION_STATE_VISIBLE) { 404 - oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, 0); 457 + oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, now_xr); 405 458 } 406 459 if (!sess->has_ended_once && sess->state != XR_SESSION_STATE_SYNCHRONIZED) { 407 - oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, 0); 460 + oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, now_xr); 408 461 // Fake the synchronization. 409 462 sess->has_ended_once = true; 410 463 } 411 464 412 465 //! @todo start fading out the app. 413 - oxr_session_change_state(log, sess, XR_SESSION_STATE_STOPPING, 0); 466 + oxr_session_change_state(log, sess, XR_SESSION_STATE_STOPPING, now_xr); 414 467 sess->exiting = true; 415 468 return oxr_session_success_result(sess); 416 469 } ··· 446 499 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "xrt_session is null"); 447 500 } 448 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 + 449 509 #ifdef XRT_OS_ANDROID 450 510 // Most recent Android activity lifecycle event was OnPause: move toward stopping 451 511 if (sess->sys->inst->activity_state == XRT_ANDROID_LIVECYCLE_EVENT_ON_PAUSE) { 452 512 if (sess->state == XR_SESSION_STATE_FOCUSED) { 453 513 U_LOG_I("Activity paused: changing session state FOCUSED->VISIBLE"); 454 - oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, 0); 514 + oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, now_xr); 455 515 } 456 516 457 517 if (sess->state == XR_SESSION_STATE_VISIBLE) { 458 518 U_LOG_I("Activity paused: changing session state VISIBLE->SYNCHRONIZED"); 459 - oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, 0); 519 + oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, now_xr); 460 520 } 461 521 462 522 if (sess->state == XR_SESSION_STATE_SYNCHRONIZED) { 463 523 U_LOG_I("Activity paused: changing session state SYNCHRONIZED->STOPPING"); 464 - oxr_session_change_state(log, sess, XR_SESSION_STATE_STOPPING, 0); 524 + oxr_session_change_state(log, sess, XR_SESSION_STATE_STOPPING, now_xr); 465 525 } 466 526 // TODO return here to avoid polling other events? 467 527 // see https://gitlab.freedesktop.org/monado/monado/-/issues/419 ··· 471 531 if (sess->sys->inst->activity_state == XRT_ANDROID_LIVECYCLE_EVENT_ON_RESUME) { 472 532 if (sess->state == XR_SESSION_STATE_IDLE) { 473 533 U_LOG_I("Activity resumed: changing session state IDLE->READY"); 474 - oxr_session_change_state(log, sess, XR_SESSION_STATE_READY, 0); 534 + oxr_session_change_state(log, sess, XR_SESSION_STATE_READY, now_xr); 475 535 } 476 536 } 477 537 #endif // XRT_OS_ANDROID ··· 491 551 case XRT_SESSION_EVENT_STATE_CHANGE: 492 552 sess->compositor_visible = xse.state.visible; 493 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 + 494 559 break; 495 560 case XRT_SESSION_EVENT_OVERLAY_CHANGE: 496 561 #ifdef OXR_HAVE_EXTX_overlay ··· 530 595 break; 531 596 case XRT_SESSION_EVENT_VISIBILITY_MASK_CHANGE: 532 597 #ifdef OXR_HAVE_KHR_visibility_mask 533 - oxr_event_push_XrEventDataVisibilityMaskChangedKHR(log, sess, sess->sys->view_config_type, 534 - xse.mask_change.view_index); 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 + } 535 607 break; 536 608 #endif // OXR_HAVE_KHR_visibility_mask 537 609 case XRT_SESSION_EVENT_USER_PRESENCE_CHANGE: ··· 545 617 } 546 618 547 619 if (sess->state == XR_SESSION_STATE_SYNCHRONIZED && sess->compositor_visible) { 548 - oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, 0); 620 + oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, now_xr); 549 621 } 550 622 551 623 if (sess->state == XR_SESSION_STATE_VISIBLE && sess->compositor_focused) { 552 - oxr_session_change_state(log, sess, XR_SESSION_STATE_FOCUSED, 0); 624 + oxr_session_change_state(log, sess, XR_SESSION_STATE_FOCUSED, now_xr); 553 625 } 554 626 555 627 if (sess->state == XR_SESSION_STATE_FOCUSED && !sess->compositor_focused) { 556 - oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, 0); 628 + oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, now_xr); 557 629 } 558 630 559 631 if (sess->state == XR_SESSION_STATE_VISIBLE && !sess->compositor_visible) { 560 - oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, 0); 632 + oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, now_xr); 561 633 } 562 634 563 635 return XR_SUCCESS; ··· 655 727 struct xrt_space_relation T_xdev_head = XRT_SPACE_RELATION_ZERO; 656 728 struct xrt_fov fovs[XRT_MAX_VIEWS] = {0}; 657 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; 658 732 659 733 xrt_result_t xret = xrt_device_get_view_poses( // 660 734 xdev, // 661 735 &default_eye_relation, // 662 736 xdisplay_time, // 737 + view_type, // 663 738 view_count, // 664 739 &T_xdev_head, // 665 740 fovs, // ··· 1047 1122 u_hashmap_int_create(&sess->act_sets_attachments_by_key); 1048 1123 u_hashmap_int_create(&sess->act_attachments_by_key); 1049 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 + 1050 1128 // Done with basic init, set out variable. 1051 1129 *out_session = sess; 1052 1130 ··· 1061 1139 } \ 1062 1140 } while (false) 1063 1141 1064 - #define OXR_CREATE_XRT_SESSION_AND_NATIVE_COMPOSITOR(LOG, XSI, SESS) \ 1142 + #define OXR_CHECK_XR_SUCCESS(LOG, FUNC, MSG) \ 1065 1143 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); \ 1144 + XrResult _xr_result = FUNC; \ 1145 + if (_xr_result != XR_SUCCESS) { \ 1146 + return oxr_error(LOG, _xr_result, MSG); \ 1081 1147 } \ 1082 1148 } while (false) 1083 1149 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) 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 + 1091 1176 1092 1177 1093 1178 /* ··· 1101 1186 const struct xrt_session_info *xsi, 1102 1187 struct oxr_session **out_session) 1103 1188 { 1189 + XrResult ret = XR_SUCCESS; 1190 + 1104 1191 #if defined(XR_USE_PLATFORM_XLIB) && defined(XR_USE_GRAPHICS_API_OPENGL) 1105 1192 XrGraphicsBindingOpenGLXlibKHR const *opengl_xlib = OXR_GET_INPUT_FROM_CHAIN( 1106 1193 createInfo, XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR, XrGraphicsBindingOpenGLXlibKHR); ··· 1113 1200 "xrGetOpenGL[ES]GraphicsRequirementsKHR"); 1114 1201 } 1115 1202 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); 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 + 1118 1209 return oxr_session_populate_gl_xlib(log, sys, opengl_xlib, *out_session); 1119 1210 } 1120 1211 #endif ··· 1132 1223 "xrGetOpenGLESGraphicsRequirementsKHR"); 1133 1224 } 1134 1225 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); 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 + 1137 1232 return oxr_session_populate_gles_android(log, sys, opengles_android, *out_session); 1138 1233 } 1139 1234 #endif ··· 1149 1244 "Has not called xrGetOpenGLGraphicsRequirementsKHR"); 1150 1245 } 1151 1246 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); 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 + 1154 1253 return oxr_session_populate_gl_win32(log, sys, opengl_win32, *out_session); 1155 1254 } 1156 1255 #endif ··· 1188 1287 (void *)vulkan->physicalDevice, (void *)sys->suggested_vulkan_physical_device, fn); 1189 1288 } 1190 1289 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); 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 + 1193 1296 return oxr_session_populate_vk(log, sys, vulkan, *out_session); 1194 1297 } 1195 1298 #endif ··· 1206 1309 "xrGetOpenGL[ES]GraphicsRequirementsKHR"); 1207 1310 } 1208 1311 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); 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 + 1211 1318 return oxr_session_populate_egl(log, sys, egl, *out_session); 1212 1319 } 1213 1320 #endif ··· 1224 1331 return oxr_error(log, XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING, 1225 1332 "Has not called xrGetD3D11GraphicsRequirementsKHR"); 1226 1333 } 1227 - XrResult result = oxr_d3d11_check_device(log, sys, d3d11->device); 1334 + ret = oxr_d3d11_check_device(log, sys, d3d11->device); 1228 1335 1229 - if (!XR_SUCCEEDED(result)) { 1230 - return result; 1336 + if (!XR_SUCCEEDED(ret)) { 1337 + return ret; 1231 1338 } 1232 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"); 1233 1342 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); 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 + 1236 1346 return oxr_session_populate_d3d11(log, sys, d3d11, *out_session); 1237 1347 } 1238 1348 #endif ··· 1249 1359 return oxr_error(log, XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING, 1250 1360 "Has not called xrGetD3D12GraphicsRequirementsKHR"); 1251 1361 } 1252 - XrResult result = oxr_d3d12_check_device(log, sys, d3d12->device); 1362 + ret = oxr_d3d12_check_device(log, sys, d3d12->device); 1253 1363 1254 - if (!XR_SUCCEEDED(result)) { 1255 - return result; 1364 + if (!XR_SUCCEEDED(ret)) { 1365 + return ret; 1256 1366 } 1257 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"); 1258 1370 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); 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 + 1261 1374 return oxr_session_populate_d3d12(log, sys, d3d12, *out_session); 1262 1375 } 1263 1376 #endif ··· 1271 1384 1272 1385 #ifdef OXR_HAVE_MND_headless 1273 1386 if (sys->inst->extensions.MND_headless) { 1274 - OXR_SESSION_ALLOCATE_AND_INIT(log, sys, OXR_SESSION_GRAPHICS_EXT_HEADLESS, *out_session); 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 + 1275 1391 (*out_session)->compositor = NULL; 1276 1392 (*out_session)->create_swapchain = NULL; 1277 1393 ··· 1320 1436 return ret; 1321 1437 } 1322 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 + 1323 1446 // 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); 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); 1326 1449 1327 1450 *out_session = sess; 1328 1451
+32 -33
src/xrt/state_trackers/oxr/oxr_session_frame_end.c
··· 38 38 #include <assert.h> 39 39 40 40 41 + 41 42 /* 42 43 * 43 44 * Helper functions and defines. ··· 334 335 #endif 335 336 } 336 337 338 + 337 339 /* 338 340 * 339 341 * Verify functions. ··· 595 597 return ret; 596 598 } 597 599 598 - switch (sess->sys->view_config_type) { 600 + switch (sess->current_view_config_type) { 599 601 case XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO: 600 602 if (proj->viewCount != 1) { 601 603 return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, ··· 612 614 layer_index, proj->viewCount); 613 615 } 614 616 break; 617 + // This also includes XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO_WITH_FOVEATED_INSET as both values are the same 615 618 case XR_VIEW_CONFIGURATION_TYPE_PRIMARY_QUAD_VARJO: 616 619 if (proj->viewCount != 4) { 617 620 return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, ··· 631 634 default: 632 635 assert(false && "view type validation unimplemented"); 633 636 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "view type %d not supported", 634 - sess->sys->view_config_type); 637 + sess->current_view_config_type); 635 638 break; 636 639 } 637 640 ··· 1164 1167 #endif 1165 1168 } 1166 1169 1170 + 1167 1171 /* 1168 1172 * 1169 1173 * Submit functions. 1170 1174 * 1171 1175 */ 1172 1176 1173 - /** 1177 + /*! 1174 1178 * Turn the poses supplied with a composition layer into the poses the compositor wants. 1175 1179 * 1176 1180 * @param log logger 1177 1181 * @param sess session 1178 1182 * @param spc space that @p pose_ptr is supplied in 1179 1183 * @param pose_ptr pose supplied with layer 1180 - * @param inv_offset inverse of the tracking origin offset 1181 1184 * @param timestamp timestamp for pose 1182 1185 * @param[out] out_pose Resulting view-space pose 1183 1186 * @return true if successfully transformed into a view space pose ··· 1187 1190 struct oxr_session *sess, 1188 1191 struct oxr_space *spc, 1189 1192 const struct xrt_pose *pose_ptr, 1190 - const struct xrt_pose *inv_offset, 1191 1193 uint64_t timestamp, 1192 1194 struct xrt_pose *out_pose) 1193 1195 { ··· 1241 1243 struct oxr_logger *log, 1242 1244 XrCompositionLayerQuad *quad, 1243 1245 struct xrt_device *head, 1244 - struct xrt_pose *inv_offset, 1245 1246 uint64_t oxr_timestamp, 1246 1247 uint64_t xrt_timestamp) 1247 1248 { ··· 1253 1254 struct xrt_pose *pose_ptr = (struct xrt_pose *)&quad->pose; 1254 1255 1255 1256 struct xrt_pose pose; 1256 - if (!handle_space(log, sess, spc, pose_ptr, inv_offset, oxr_timestamp, &pose)) { 1257 + if (!handle_space(log, sess, spc, pose_ptr, oxr_timestamp, &pose)) { 1257 1258 return XR_SUCCESS; 1258 1259 } 1259 1260 ··· 1292 1293 struct oxr_logger *log, 1293 1294 XrCompositionLayerProjection *proj, 1294 1295 struct xrt_device *head, 1295 - struct xrt_pose *inv_offset, 1296 1296 uint64_t oxr_timestamp, 1297 1297 uint64_t xrt_timestamp) 1298 1298 { ··· 1316 1316 scs[i] = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_swapchain *, proj->views[i].subImage.swapchain); 1317 1317 pose_ptr = (struct xrt_pose *)&proj->views[i].pose; 1318 1318 1319 - if (!handle_space(log, sess, spc, pose_ptr, inv_offset, oxr_timestamp, &pose[i])) { 1319 + if (!handle_space(log, sess, spc, pose_ptr, oxr_timestamp, &pose[i])) { 1320 1320 return XR_SUCCESS; 1321 1321 } 1322 1322 } ··· 1398 1398 struct oxr_logger *log, 1399 1399 const XrCompositionLayerCubeKHR *cube, 1400 1400 struct xrt_device *head, 1401 - struct xrt_pose *inv_offset, 1402 1401 uint64_t oxr_timestamp, 1403 1402 uint64_t xrt_timestamp) 1404 1403 { ··· 1437 1436 .position = XRT_VEC3_ZERO, 1438 1437 }; 1439 1438 1440 - if (!handle_space(log, sess, spc, &pose, inv_offset, oxr_timestamp, &data.cube.pose)) { 1439 + if (!handle_space(log, sess, spc, &pose, oxr_timestamp, &data.cube.pose)) { 1441 1440 return XR_SUCCESS; 1442 1441 } 1443 1442 ··· 1453 1452 struct oxr_logger *log, 1454 1453 const XrCompositionLayerCylinderKHR *cylinder, 1455 1454 struct xrt_device *head, 1456 - struct xrt_pose *inv_offset, 1457 1455 uint64_t oxr_timestamp, 1458 1456 uint64_t xrt_timestamp) 1459 1457 { ··· 1466 1464 struct xrt_pose *pose_ptr = (struct xrt_pose *)&cylinder->pose; 1467 1465 1468 1466 struct xrt_pose pose; 1469 - if (!handle_space(log, sess, spc, pose_ptr, inv_offset, oxr_timestamp, &pose)) { 1467 + if (!handle_space(log, sess, spc, pose_ptr, oxr_timestamp, &pose)) { 1470 1468 return XR_SUCCESS; 1471 1469 } 1472 1470 ··· 1505 1503 struct oxr_logger *log, 1506 1504 const XrCompositionLayerEquirectKHR *equirect, 1507 1505 struct xrt_device *head, 1508 - struct xrt_pose *inv_offset, 1509 1506 uint64_t oxr_timestamp, 1510 1507 uint64_t xrt_timestamp) 1511 1508 { ··· 1517 1514 struct xrt_pose *pose_ptr = (struct xrt_pose *)&equirect->pose; 1518 1515 1519 1516 struct xrt_pose pose; 1520 - if (!handle_space(log, sess, spc, pose_ptr, inv_offset, oxr_timestamp, &pose)) { 1517 + if (!handle_space(log, sess, spc, pose_ptr, oxr_timestamp, &pose)) { 1521 1518 return XR_SUCCESS; 1522 1519 } 1523 1520 ··· 1554 1551 } 1555 1552 1556 1553 static void 1557 - do_synchronize_state_change(struct oxr_logger *log, struct oxr_session *sess) 1554 + do_synchronize_state_change(struct oxr_logger *log, struct oxr_session *sess, XrTime time) 1558 1555 { 1559 1556 if (!sess->has_ended_once && sess->state < XR_SESSION_STATE_VISIBLE) { 1560 - oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, 0); 1557 + oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, time); 1561 1558 sess->has_ended_once = true; 1562 1559 } 1563 1560 } ··· 1568 1565 struct oxr_logger *log, 1569 1566 const XrCompositionLayerEquirect2KHR *equirect, 1570 1567 struct xrt_device *head, 1571 - struct xrt_pose *inv_offset, 1572 1568 uint64_t oxr_timestamp, 1573 1569 uint64_t xrt_timestamp) 1574 1570 { ··· 1580 1576 struct xrt_pose *pose_ptr = (struct xrt_pose *)&equirect->pose; 1581 1577 1582 1578 struct xrt_pose pose; 1583 - if (!handle_space(log, sess, spc, pose_ptr, inv_offset, oxr_timestamp, &pose)) { 1579 + if (!handle_space(log, sess, spc, pose_ptr, oxr_timestamp, &pose)) { 1584 1580 return XR_SUCCESS; 1585 1581 } 1586 1582 ··· 1619 1615 struct oxr_logger *log, 1620 1616 const XrCompositionLayerPassthroughFB *passthrough, 1621 1617 struct xrt_device *head, 1622 - struct xrt_pose *inv_offset, 1623 1618 uint64_t oxr_timestamp, 1624 1619 uint64_t xrt_timestamp) 1625 1620 { ··· 1668 1663 struct xrt_compositor *xc = sess->compositor; 1669 1664 1670 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 + 1671 1673 /* 1672 1674 * Early out for headless sessions. 1673 1675 */ ··· 1678 1680 sess->active_wait_frames--; 1679 1681 os_mutex_unlock(&sess->active_wait_frames_lock); 1680 1682 1681 - do_synchronize_state_change(log, sess); 1683 + do_synchronize_state_change(log, sess, now_xr); 1682 1684 1683 1685 return oxr_session_success_result(sess); 1684 1686 } ··· 1721 1723 sess->frame_id.begun = -1; 1722 1724 sess->frame_started = false; 1723 1725 1724 - do_synchronize_state_change(log, sess); 1726 + do_synchronize_state_change(log, sess, now_xr); 1725 1727 1726 1728 return oxr_session_success_result(sess); 1727 1729 } ··· 1790 1792 */ 1791 1793 1792 1794 // 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); 1795 + do_synchronize_state_change(log, sess, now_xr); 1797 1796 1798 1797 struct xrt_layer_frame_data data = { 1799 1798 .frame_id = sess->frame_id.begun, ··· 1811 1810 1812 1811 switch (layer->type) { 1813 1812 case XR_TYPE_COMPOSITION_LAYER_PROJECTION: 1814 - submit_projection_layer(sess, xc, log, (XrCompositionLayerProjection *)layer, xdev, &inv_offset, 1813 + submit_projection_layer(sess, xc, log, (XrCompositionLayerProjection *)layer, xdev, 1815 1814 frameEndInfo->displayTime, xrt_display_time_ns); 1816 1815 break; 1817 1816 case XR_TYPE_COMPOSITION_LAYER_QUAD: 1818 - submit_quad_layer(sess, xc, log, (XrCompositionLayerQuad *)layer, xdev, &inv_offset, 1817 + submit_quad_layer(sess, xc, log, (XrCompositionLayerQuad *)layer, xdev, 1819 1818 frameEndInfo->displayTime, xrt_display_time_ns); 1820 1819 break; 1821 1820 case XR_TYPE_COMPOSITION_LAYER_CUBE_KHR: 1822 - submit_cube_layer(sess, xc, log, (XrCompositionLayerCubeKHR *)layer, xdev, &inv_offset, 1821 + submit_cube_layer(sess, xc, log, (XrCompositionLayerCubeKHR *)layer, xdev, 1823 1822 frameEndInfo->displayTime, xrt_display_time_ns); 1824 1823 break; 1825 1824 case XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR: 1826 - submit_cylinder_layer(sess, xc, log, (XrCompositionLayerCylinderKHR *)layer, xdev, &inv_offset, 1825 + submit_cylinder_layer(sess, xc, log, (XrCompositionLayerCylinderKHR *)layer, xdev, 1827 1826 frameEndInfo->displayTime, xrt_display_time_ns); 1828 1827 break; 1829 1828 case XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR: 1830 - submit_equirect1_layer(sess, xc, log, (XrCompositionLayerEquirectKHR *)layer, xdev, &inv_offset, 1829 + submit_equirect1_layer(sess, xc, log, (XrCompositionLayerEquirectKHR *)layer, xdev, 1831 1830 frameEndInfo->displayTime, xrt_display_time_ns); 1832 1831 break; 1833 1832 case XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR: 1834 1833 submit_equirect2_layer(sess, xc, log, (XrCompositionLayerEquirect2KHR *)layer, xdev, 1835 - &inv_offset, frameEndInfo->displayTime, xrt_display_time_ns); 1834 + frameEndInfo->displayTime, xrt_display_time_ns); 1836 1835 break; 1837 1836 case XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB: 1838 1837 submit_passthrough_layer(sess, xc, log, (XrCompositionLayerPassthroughFB *)layer, xdev, 1839 - &inv_offset, frameEndInfo->displayTime, xrt_display_time_ns); 1838 + frameEndInfo->displayTime, xrt_display_time_ns); 1840 1839 break; 1841 1840 default: assert(false && "invalid layer type"); 1842 1841 }
+18
src/xrt/state_trackers/oxr/oxr_space.c
··· 1 1 // Copyright 2019-2024, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 612 613 613 614 return ret; 614 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 18 #include "util/u_debug.h" 19 19 #include "util/u_verify.h" 20 20 21 + #include "oxr_api_verify.h" 22 + #include "oxr_chain.h" 23 + #include "oxr_conversions.h" 21 24 #include "oxr_objects.h" 22 25 #include "oxr_logger.h" 23 26 #include "oxr_two_call.h" 24 - #include "oxr_chain.h" 25 - #include "oxr_api_verify.h" 26 - #include "oxr_conversions.h" 27 27 28 28 29 + /* 30 + * 31 + * General helpers 32 + * 33 + */ 34 + 29 35 DEBUG_GET_ONCE_NUM_OPTION(scale_percentage, "OXR_VIEWPORT_SCALE_PERCENTAGE", 100) 30 36 31 37 32 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 + 33 125 static bool 34 126 oxr_system_matches(struct oxr_logger *log, struct oxr_system *sys, XrFormFactor form_factor) 35 127 { 36 128 return xr_form_factor_to_xrt(form_factor) == sys->xsys->properties.form_factor; 37 129 } 38 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 + 39 184 XrResult 40 185 oxr_system_select(struct oxr_logger *log, 41 186 struct oxr_system **systems, ··· 98 243 return XR_SUCCESS; 99 244 } 100 245 101 - 102 - 103 246 XrResult 104 247 oxr_system_fill_in( 105 248 struct oxr_logger *log, struct oxr_instance *inst, XrSystemId systemId, uint32_t view_count, struct oxr_system *sys) ··· 108 251 109 252 sys->inst = inst; 110 253 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 254 sys->dynamic_roles_cache = (struct xrt_system_roles)XRT_SYSTEM_ROLES_INIT; 120 255 121 256 #ifdef XR_USE_GRAPHICS_API_VULKAN 122 257 sys->vulkan_enable2_instance = VK_NULL_HANDLE; 123 258 sys->suggested_vulkan_physical_device = VK_NULL_HANDLE; 259 + sys->vk_get_instance_proc_addr = VK_NULL_HANDLE; 124 260 #endif 125 261 #if defined(XR_USE_GRAPHICS_API_D3D11) || defined(XR_USE_GRAPHICS_API_D3D12) 126 262 U_ZERO(&(sys->suggested_d3d_luid)); 127 263 sys->suggested_d3d_luid_valid = false; 128 264 #endif 129 265 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 - } 266 + if (sys->xsysc != NULL) { 267 + const struct xrt_system_compositor_info *info = &sys->xsysc->info; 136 268 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 - } 269 + for (uint32_t i = 0; i < info->view_config_count; i++) { 270 + const struct xrt_view_config *view_config = &info->view_configs[i]; 162 271 163 - #undef imin 164 - 165 - 166 - /* 167 - * Blend mode support. 168 - */ 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); 169 283 170 - assert(info->supported_blend_mode_count <= ARRAY_SIZE(sys->blend_modes)); 171 - assert(info->supported_blend_mode_count != 0); 284 + enum xrt_view_type view_type = view_count == 1 ? XRT_VIEW_TYPE_MONO : XRT_VIEW_TYPE_STEREO; 172 285 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]; 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++; 176 290 } 177 - sys->blend_mode_count = (uint32_t)info->supported_blend_mode_count; 178 291 179 292 180 293 /* ··· 290 403 OXR_CHECK_RET_IS_FFB_SUPPORTED(conforming_right) 291 404 #undef OXR_CHECK_RET_IS_FFB_SUPPORTED 292 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 + } 293 428 } 294 429 295 430 void ··· 351 486 return; 352 487 } 353 488 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 489 bool 375 490 oxr_system_get_body_tracking_fb_support(struct oxr_logger *log, struct oxr_instance *inst) 376 491 { ··· 475 590 } 476 591 #endif 477 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 + 478 607 #ifdef OXR_HAVE_HTC_facial_tracking 479 608 XrSystemFacialTrackingPropertiesHTC *htc_facial_tracking_props = NULL; 480 609 if (sys->inst->extensions.HTC_facial_tracking) { ··· 595 724 uint32_t *viewConfigurationTypeCountOutput, 596 725 XrViewConfigurationType *viewConfigurationTypes) 597 726 { 598 - OXR_TWO_CALL_HELPER(log, viewConfigurationTypeCapacityInput, viewConfigurationTypeCountOutput, 599 - viewConfigurationTypes, 1, &sys->view_config_type, XR_SUCCESS); 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); 600 730 } 601 731 602 732 XrResult ··· 607 737 uint32_t *environmentBlendModeCountOutput, 608 738 XrEnvironmentBlendMode *environmentBlendModes) 609 739 { 610 - //! @todo Take into account viewConfigurationType 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 + 611 745 OXR_TWO_CALL_HELPER(log, environmentBlendModeCapacityInput, environmentBlendModeCountOutput, 612 - environmentBlendModes, sys->blend_mode_count, sys->blend_modes, XR_SUCCESS); 746 + environmentBlendModes, props->blend_mode_count, props->blend_modes, XR_SUCCESS); 613 747 } 614 748 615 749 XrResult ··· 618 752 XrViewConfigurationType viewConfigurationType, 619 753 XrViewConfigurationProperties *configurationProperties) 620 754 { 621 - if (viewConfigurationType != sys->view_config_type) { 622 - return oxr_error(log, XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED, "Invalid view configuration type"); 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"); 623 758 } 624 759 625 - configurationProperties->viewConfigurationType = sys->view_config_type; 760 + configurationProperties->viewConfigurationType = props->view_config_type; 626 761 configurationProperties->fovMutable = sys->xsysc->info.supports_fov_mutable; 627 762 628 763 return XR_SUCCESS; 629 764 } 630 765 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 766 XrResult 645 767 oxr_system_enumerate_view_conf_views(struct oxr_logger *log, 646 768 struct oxr_system *sys, ··· 649 771 uint32_t *viewCountOutput, 650 772 XrViewConfigurationView *views) 651 773 { 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); 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"); 661 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); 662 781 }
+36 -12
src/xrt/state_trackers/oxr/oxr_two_call.h
··· 14 14 extern "C" { 15 15 #endif 16 16 17 - 18 - #define OXR_TWO_CALL_HELPER(log, cnt_input, cnt_output, output, count, data, sval) \ 17 + #define OXR_TWO_CALL_CHECK_ONLY(log, cnt_input, cnt_output, count, sval) \ 19 18 do { \ 20 19 if ((cnt_output) == NULL) { \ 21 20 return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, #cnt_output); \ ··· 28 27 if ((cnt_input) < (uint32_t)(count)) { \ 29 28 return oxr_error(log, XR_ERROR_SIZE_INSUFFICIENT, #cnt_input); \ 30 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 + \ 31 53 for (uint32_t i = 0; i < (count); i++) { \ 32 54 (output)[i] = (data)[i]; \ 33 55 } \ ··· 37 59 //! Calls fill_fn(&output_struct[i], &source_struct[i]) to fill output_structs 38 60 #define OXR_TWO_CALL_FILL_IN_HELPER(log, cnt_input, cnt_output, output_structs, count, fill_fn, source_structs, sval) \ 39 61 do { \ 40 - if (cnt_output == NULL) { \ 41 - return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, #cnt_output); \ 42 - } \ 43 - *cnt_output = count; \ 62 + OXR_TWO_CALL_CHECK_ONLY(log, cnt_input, cnt_output, count, sval); \ 44 63 \ 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 64 for (uint32_t i = 0; i < count; i++) { \ 52 65 fill_fn(&output_structs[i], &source_structs[i]); \ 53 66 } \ 54 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 + } \ 55 79 } while (false) 56 80 57 81 #ifdef __cplusplus
+22
src/xrt/state_trackers/oxr/oxr_verify.c
··· 1 1 // Copyright 2018-2022, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 424 425 } 425 426 #endif 426 427 428 + #ifdef OXR_HAVE_EXT_dpad_binding 427 429 if (extensions->EXT_dpad_binding && !extensions->KHR_binding_modification) { 428 430 return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, 429 431 "XR_EXT_dpad_binding requires XR_KHR_binding_modification"); 430 432 } 433 + #endif 431 434 432 435 return XR_SUCCESS; 433 436 } ··· 444 447 return XR_SUCCESS; 445 448 } 446 449 450 + // Valid in OpenXR 1.1 and forward. 447 451 if (OXR_API_VERSION_AT_LEAST(inst, 1, 1)) { 448 452 if (view_conf == XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO_WITH_FOVEATED_INSET) { 449 453 return XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED; ··· 452 456 453 457 return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, "(%s == 0x%08x) invalid view configuration type", 454 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); 455 477 } 456 478 457 479 XrResult
+41 -45
src/xrt/state_trackers/oxr/oxr_vulkan.c
··· 1 1 // Copyright 2018-2024, Collabora, Ltd. 2 + // Copyright 2024-2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 31 32 * 32 33 */ 33 34 34 - #define GET_PROC(name) PFN_##name name = (PFN_##name)getProc(vkInstance, #name) 35 + #define GET_PROC(INST, NAME) PFN_vk##NAME loaded_##NAME = (PFN_vk##NAME)vulkanGetInstanceProcAddr(INST, "vk" #NAME) 35 36 36 37 #define UUID_STR_SIZE (XRT_UUID_SIZE * 3 + 1) 37 38 ··· 190 191 191 192 static XrResult 192 193 vk_get_instance_ext_props(struct oxr_logger *log, 193 - VkInstance instance, 194 - PFN_vkGetInstanceProcAddr GetInstanceProcAddr, 194 + VkInstance vulkanInstance, 195 + PFN_vkGetInstanceProcAddr vulkanGetInstanceProcAddr, 195 196 VkExtensionProperties **out_props, 196 197 uint32_t *out_prop_count) 197 198 { 198 - PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties = 199 - (PFN_vkEnumerateInstanceExtensionProperties)vkGetInstanceProcAddr(NULL, 200 - "vkEnumerateInstanceExtensionProperties"); 199 + GET_PROC(vulkanInstance, EnumerateInstanceExtensionProperties); 201 200 202 - if (!EnumerateInstanceExtensionProperties) { 201 + if (!loaded_EnumerateInstanceExtensionProperties) { 203 202 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, 204 - "Failed to get EnumerateInstanceExtensionProperties fp"); 203 + "Failed to get vkEnumerateInstanceExtensionProperties function pointer."); 205 204 } 206 205 207 206 uint32_t prop_count = 0; 208 - VkResult res = EnumerateInstanceExtensionProperties(NULL, &prop_count, NULL); 207 + VkResult res = loaded_EnumerateInstanceExtensionProperties(NULL, &prop_count, NULL); 209 208 if (res != VK_SUCCESS) { 210 209 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, 211 210 "Failed to enumerate instance extension properties count (%d)", res); ··· 214 213 215 214 VkExtensionProperties *props = U_TYPED_ARRAY_CALLOC(VkExtensionProperties, prop_count); 216 215 217 - res = EnumerateInstanceExtensionProperties(NULL, &prop_count, props); 216 + res = loaded_EnumerateInstanceExtensionProperties(NULL, &prop_count, props); 218 217 if (res != VK_SUCCESS) { 219 218 free(props); 220 219 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, ··· 235 234 VkResult *vulkanResult) 236 235 { 237 236 238 - PFN_vkGetInstanceProcAddr GetInstanceProcAddr = createInfo->pfnGetInstanceProcAddr; 237 + PFN_vkGetInstanceProcAddr vulkanGetInstanceProcAddr = createInfo->pfnGetInstanceProcAddr; 238 + GET_PROC(NULL, CreateInstance); 239 239 240 - PFN_vkCreateInstance CreateInstance = (PFN_vkCreateInstance)GetInstanceProcAddr(NULL, "vkCreateInstance"); 241 - if (!CreateInstance) { 240 + if (!loaded_CreateInstance) { 242 241 //! @todo: clarify in spec 243 242 *vulkanResult = VK_ERROR_INITIALIZATION_FAILED; 244 243 return XR_SUCCESS; ··· 284 283 modified_info.ppEnabledExtensionNames = u_string_list_get_data(instance_ext_list); 285 284 modified_info.enabledExtensionCount = u_string_list_get_size(instance_ext_list); 286 285 287 - *vulkanResult = CreateInstance(&modified_info, createInfo->vulkanAllocator, vulkanInstance); 286 + *vulkanResult = loaded_CreateInstance(&modified_info, createInfo->vulkanAllocator, vulkanInstance); 288 287 289 288 290 289 // Logging ··· 315 314 316 315 static XrResult 317 316 vk_get_device_ext_props(struct oxr_logger *log, 318 - VkInstance instance, 319 - PFN_vkGetInstanceProcAddr GetInstanceProcAddr, 317 + VkInstance vulkanInstance, 318 + PFN_vkGetInstanceProcAddr vulkanGetInstanceProcAddr, 320 319 VkPhysicalDevice physical_device, 321 320 VkExtensionProperties **out_props, 322 321 uint32_t *out_prop_count) 323 322 { 324 - PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties = 325 - (PFN_vkEnumerateDeviceExtensionProperties)GetInstanceProcAddr(instance, 326 - "vkEnumerateDeviceExtensionProperties"); 323 + GET_PROC(vulkanInstance, EnumerateDeviceExtensionProperties); 327 324 328 - if (!EnumerateDeviceExtensionProperties) { 325 + if (!loaded_EnumerateDeviceExtensionProperties) { 329 326 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, 330 - "Failed to get vkEnumerateDeviceExtensionProperties fp"); 327 + "Failed to get vkEnumerateDeviceExtensionProperties function pointer"); 331 328 } 332 329 333 330 uint32_t prop_count = 0; 334 - VkResult res = EnumerateDeviceExtensionProperties(physical_device, NULL, &prop_count, NULL); 331 + VkResult res = loaded_EnumerateDeviceExtensionProperties(physical_device, NULL, &prop_count, NULL); 335 332 if (res != VK_SUCCESS) { 336 333 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, 337 334 "Failed to enumerate device extension properties count (%d)", res); ··· 340 337 341 338 VkExtensionProperties *props = U_TYPED_ARRAY_CALLOC(VkExtensionProperties, prop_count); 342 339 343 - res = EnumerateDeviceExtensionProperties(physical_device, NULL, &prop_count, props); 340 + res = loaded_EnumerateDeviceExtensionProperties(physical_device, NULL, &prop_count, props); 344 341 if (res != VK_SUCCESS) { 345 342 free(props); 346 343 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to enumerate device extension properties (%d)", ··· 355 352 356 353 static XrResult 357 354 vk_get_device_features(struct oxr_logger *log, 358 - VkInstance instance, 359 - PFN_vkGetInstanceProcAddr GetInstanceProcAddr, 355 + VkInstance vulkanInstance, 356 + PFN_vkGetInstanceProcAddr vulkanGetInstanceProcAddr, 360 357 VkPhysicalDevice physical_device, 361 358 VkPhysicalDeviceFeatures2KHR *physical_device_features) 362 359 { 363 - PFN_vkGetPhysicalDeviceFeatures2KHR GetPhysicalDeviceFeatures2 = 364 - (PFN_vkGetPhysicalDeviceFeatures2KHR)GetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2KHR"); 360 + GET_PROC(vulkanInstance, GetPhysicalDeviceFeatures2KHR); 365 361 366 - if (!GetPhysicalDeviceFeatures2) { 367 - oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to get vkGetPhysicalDeviceFeatures2 fp"); 362 + if (!loaded_GetPhysicalDeviceFeatures2KHR) { 363 + oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to get vkGetPhysicalDeviceFeatures2KHR fp"); 368 364 } 369 365 370 - GetPhysicalDeviceFeatures2( // 371 - physical_device, // physicalDevice 372 - physical_device_features); // pFeatures 366 + loaded_GetPhysicalDeviceFeatures2KHR( // 367 + physical_device, // physicalDevice 368 + physical_device_features); // pFeatures 373 369 374 370 return XR_SUCCESS; 375 371 } ··· 395 391 { 396 392 XrResult res; 397 393 398 - PFN_vkGetInstanceProcAddr GetInstanceProcAddr = createInfo->pfnGetInstanceProcAddr; 394 + PFN_vkGetInstanceProcAddr vulkanGetInstanceProcAddr = createInfo->pfnGetInstanceProcAddr; 395 + GET_PROC(sys->vulkan_enable2_instance, CreateDevice); 399 396 400 - PFN_vkCreateDevice CreateDevice = 401 - (PFN_vkCreateDevice)GetInstanceProcAddr(sys->vulkan_enable2_instance, "vkCreateDevice"); 402 - if (!CreateDevice) { 397 + if (!loaded_CreateDevice) { 403 398 //! @todo: clarify in spec 404 399 *vulkanResult = VK_ERROR_INITIALIZATION_FAILED; 405 400 return XR_SUCCESS; ··· 513 508 } 514 509 #endif 515 510 516 - *vulkanResult = CreateDevice(physical_device, &modified_info, createInfo->vulkanAllocator, vulkanDevice); 511 + *vulkanResult = loaded_CreateDevice(physical_device, &modified_info, createInfo->vulkanAllocator, vulkanDevice); 517 512 518 513 519 514 // Logging ··· 571 566 oxr_vk_get_physical_device(struct oxr_logger *log, 572 567 struct oxr_instance *inst, 573 568 struct oxr_system *sys, 574 - VkInstance vkInstance, 575 - PFN_vkGetInstanceProcAddr getProc, 569 + VkInstance vulkanInstance, 570 + PFN_vkGetInstanceProcAddr vulkanGetInstanceProcAddr, 576 571 VkPhysicalDevice *vkPhysicalDevice) 577 572 { 578 - GET_PROC(vkEnumeratePhysicalDevices); 579 - GET_PROC(vkGetPhysicalDeviceProperties2KHR); 573 + GET_PROC(vulkanInstance, EnumeratePhysicalDevices); 574 + GET_PROC(vulkanInstance, GetPhysicalDeviceProperties2KHR); 575 + 580 576 VkResult vk_ret; 581 577 uint32_t count; 582 578 ··· 584 580 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, " sys->xsysc == NULL"); 585 581 } 586 582 587 - vk_ret = vkEnumeratePhysicalDevices(vkInstance, &count, NULL); 583 + vk_ret = loaded_EnumeratePhysicalDevices(vulkanInstance, &count, NULL); 588 584 if (vk_ret != VK_SUCCESS) { 589 585 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Call to vkEnumeratePhysicalDevices returned %u", 590 586 vk_ret); ··· 595 591 } 596 592 597 593 VkPhysicalDevice *phys = U_TYPED_ARRAY_CALLOC(VkPhysicalDevice, count); 598 - vk_ret = vkEnumeratePhysicalDevices(vkInstance, &count, phys); 594 + vk_ret = loaded_EnumeratePhysicalDevices(vulkanInstance, &count, phys); 599 595 if (vk_ret != VK_SUCCESS) { 600 596 free(phys); 601 597 return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Call to vkEnumeratePhysicalDevices returned %u", ··· 622 618 .pNext = &pdidp, 623 619 }; 624 620 625 - vkGetPhysicalDeviceProperties2KHR(phys[i], &pdp2); 621 + loaded_GetPhysicalDeviceProperties2KHR(phys[i], &pdp2); 626 622 627 623 // These should always be true 628 624 static_assert(VK_UUID_SIZE == XRT_UUID_SIZE, "uuid sizes mismatch"); ··· 656 652 657 653 // vulkan_enable2 needs the physical device in xrCreateVulkanDeviceKHR 658 654 if (inst->extensions.KHR_vulkan_enable2) { 659 - sys->vulkan_enable2_instance = vkInstance; 655 + sys->vulkan_enable2_instance = vulkanInstance; 660 656 } 661 657 sys->suggested_vulkan_physical_device = *vkPhysicalDevice; 662 658 if (log_level <= U_LOGGING_DEBUG) {
+22 -2
src/xrt/state_trackers/oxr/oxr_xret.h
··· 24 24 xrt_result_t check_ret = (RESULTS); \ 25 25 if (check_ret == XRT_ERROR_IPC_FAILURE) { \ 26 26 (SESS)->has_lost = true; \ 27 - return oxr_error(LOG, XR_ERROR_INSTANCE_LOST, "Call to " #FUNCTION " failed"); \ 27 + return oxr_error((LOG), XR_ERROR_INSTANCE_LOST, "Call to " #FUNCTION " failed"); \ 28 28 } \ 29 29 if (check_ret != XRT_SUCCESS) { \ 30 - return oxr_error(LOG, XR_ERROR_RUNTIME_FAILURE, "Call to " #FUNCTION " failed"); \ 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; \ 31 51 } \ 32 52 } while (false)
+2 -1
src/xrt/state_trackers/steamvr_drv/ovrd_driver.cpp
··· 1108 1108 1109 1109 //! @todo more than 2 views 1110 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); 1111 + xrt_device_get_view_poses(xdev, &ipd_vec, now_ns, XRT_VIEW_TYPE_STEREO, 2, &head_relation, m_fovs, 1112 + m_view_pose); 1112 1113 1113 1114 //! @todo more versatile IPD calculation 1114 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 1 // Copyright 2020-2024, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 50 51 * Internal functions. 51 52 * 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 + } 53 66 54 67 static xrt_result_t 55 68 t_instance_create_system(struct xrt_instance *xinst, ··· 168 181 } 169 182 170 183 struct t_instance *tinst = U_TYPED_CALLOC(struct t_instance); 184 + tinst->base.is_system_available = t_instance_is_system_available; 171 185 tinst->base.create_system = t_instance_create_system; 172 186 tinst->base.get_prober = t_instance_get_prober; 173 187 tinst->base.destroy = t_instance_destroy;
+11
src/xrt/targets/ctl/main.c
··· 1 1 // Copyright 2020-2024, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 314 315 if (xret != XRT_SUCCESS) { 315 316 U_LOG_E("ipc_client_connection_init: %u", xret); 316 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!"); 317 328 } 318 329 319 330 switch (op_mode) {
+11
src/xrt/targets/libmonado/monado.c
··· 1 1 // Copyright 2019-2024, Collabora, Ltd. 2 + // Copyright 2025, NVIDIA CORPORATION. 2 3 // SPDX-License-Identifier: BSL-1.0 3 4 /*! 4 5 * @file ··· 145 146 PE("Connection init error '%i'!\n", xret); 146 147 free(r); 147 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!"); 148 159 } 149 160 150 161 *out_root = r;
+28 -19
src/xrt/targets/sdl_test/sdl_compositor.c
··· 43 43 return &c->base.vk; 44 44 } 45 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__); 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 51 52 52 53 53 /* ··· 246 246 struct comp_vulkan_formats formats = {0}; 247 247 comp_vulkan_formats_check(vk, &formats); 248 248 comp_vulkan_formats_copy_to_info(&formats, info); 249 - comp_vulkan_formats_log(c->base.vk.log_level, &formats); 249 + comp_vulkan_formats_log(vk->log_level, &formats); 250 250 251 251 return true; 252 252 } ··· 256 256 { 257 257 struct xrt_system_compositor_info *sys_info = &c->sys_info; 258 258 259 - // Required by OpenXR spec. 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 + */ 260 266 sys_info->max_layers = XRT_MAX_LAYERS; 261 267 262 268 // UUIDs and LUID already set in vk init. ··· 277 283 } 278 284 279 285 // 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 + 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; 286 295 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; 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; 293 302 // clang-format on 294 303 295 304 // Copy the list directly.
+4
src/xrt/targets/service/main.c
··· 11 11 12 12 #include "xrt/xrt_config_os.h" 13 13 14 + #include "util/u_debug.h" 14 15 #include "util/u_metrics.h" 15 16 #include "util/u_logging.h" 16 17 #include "util/u_trace_marker.h" ··· 22 23 #include "server/ipc_server_interface.h" 23 24 24 25 #include "target_lists.h" 26 + 27 + DEBUG_GET_ONCE_BOOL_OPTION(exit_on_disconnect, "IPC_EXIT_ON_DISCONNECT", false) 25 28 26 29 27 30 // Insert the on load constructor to init trace marker. ··· 44 47 .window_title = "Monado! โœจโšก๐Ÿ”ฅ", 45 48 .open = U_DEBUG_GUI_OPEN_AUTO, 46 49 }, 50 + .exit_on_disconnect = debug_get_bool_option_exit_on_disconnect(), 47 51 }; 48 52 49 53 int ret = ipc_server_main(argc, argv, &ismi);
+14
src/xrt/targets/service-lib/service_target.cpp
··· 78 78 // No-op 79 79 } 80 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 + 81 93 int32_t 82 94 addClient(int fd) 83 95 { ··· 140 152 .init_failed = signalInitFailed, 141 153 .mainloop_entering = signalStartupCompleteTrampoline, 142 154 .mainloop_leaving = signalShuttingDownTrampoline, 155 + .client_connected = signalClientConnectedTrampoline, 156 + .client_disconnected = signalClientDisconnectedTrampoline, 143 157 }; 144 158 145 159 //! Reference to the ipc_server, managed by ipc_server_process
-1
src/xrt/tracking/hand/mercury/hg_sync.cpp
··· 25 25 26 26 27 27 namespace xrt::tracking::hand::mercury { 28 - #define DEG_TO_RAD(DEG) (DEG * M_PI / 180.) 29 28 30 29 DEBUG_GET_ONCE_LOG_OPTION(mercury_log, "MERCURY_LOG", U_LOGGING_WARN) 31 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 137 struct xrt_space_relation wrist_rel = 138 138 hta->working.hands[i].values.hand_joint_set_default[XRT_HAND_JOINT_WRIST].relation; 139 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); // 140 + m_relation_history_push_with_motion_estimation( // 141 + hta->present.relation_hist[i], // 142 + &wrist_rel, // 143 + hta->working.timestamp); // 150 144 } 151 145 152 146 hta->hand_tracking_work_active = false;
+7 -1
tests/CMakeLists.txt
··· 27 27 list(APPEND tests tests_aux_d3d_d3d11 tests_comp_client_d3d11) 28 28 endif() 29 29 if(XRT_HAVE_D3D12) 30 - list(APPEND tests tests_comp_client_d3d12) 30 + list(APPEND tests tests_aux_d3d_d3d12 tests_comp_client_d3d12) 31 31 endif() 32 32 if(XRT_HAVE_VULKAN) 33 33 list(APPEND tests tests_comp_client_vulkan tests_uv_to_tangent) ··· 52 52 target_link_libraries(${testname} PRIVATE xrt-external-catch2) 53 53 target_link_libraries(${testname} PRIVATE aux_util) 54 54 add_test(NAME ${testname} COMMAND ${testname} --success --allow-running-no-tests) 55 + set_target_properties(${testname} PROPERTIES FOLDER monado_tests) 55 56 endforeach() 56 57 57 58 # For tests that require more than just aux_util, link those other libs down here. ··· 86 87 endif() 87 88 88 89 if(XRT_HAVE_D3D12) 90 + target_link_libraries(tests_aux_d3d_d3d12 PRIVATE aux_d3d) 89 91 target_link_libraries(tests_comp_client_d3d12 PRIVATE comp_client comp_mock) 90 92 endif() 91 93 ··· 111 113 if(XRT_HAVE_VULKAN AND XRT_HAVE_D3D11) 112 114 target_link_libraries(tests_aux_d3d_d3d11 PRIVATE comp_util aux_vk) 113 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 88 std::vector<xrt_image_native> xins; 89 89 xins.reserve(image_count); 90 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 91 for (HANDLE handle : handles) { 96 - wil::unique_handle duped{u_graphics_buffer_ref(handle)}; 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 + */ 97 100 xrt_image_native xin; 98 - xin.handle = duped.get(); 101 + xin.handle = handle; 99 102 xin.size = 0; 100 103 xin.use_dedicated_allocation = use_dedicated_allocation; 104 + xin.is_dxgi_handle = true; 101 105 102 - handlesForImport.emplace_back(std::move(duped)); 103 106 xins.emplace_back(xin); 104 107 } 105 108 106 109 // 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()); 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); 108 112 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; 113 + return true; 116 114 } 117 115 #else 118 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 + }