+1
-2
.gitlab-ci/templates/.gitlab-ci.yml.jinja
+1
-2
.gitlab-ci/templates/.gitlab-ci.yml.jinja
···
142
- .gitlab-ci/ci-cmake-build.sh {{- make_cmake_args(job.cmake_defines) }}
143
{%- if job.pahole %}
144
145
-
- src/xrt/ipc/shared/proto.py src/xrt/ipc/shared/proto.json structs.txt
146
- mkdir -p "{{ job.name}}"
147
-
- pahole --sizes --class_name file://structs.txt build/src/xrt/targets/openxr/libopenxr_monado.so > "{{ job.name}}/ipc-sizes.txt"{% endif %}
148
149
{#- gradle builds -#}
150
{%- elif "android" in job.name %}
···
142
- .gitlab-ci/ci-cmake-build.sh {{- make_cmake_args(job.cmake_defines) }}
143
{%- if job.pahole %}
144
145
- mkdir -p "{{ job.name}}"
146
+
- pahole --sizes --class_name file://build/ipc-structs.txt build/src/xrt/targets/openxr/libopenxr_monado.so > "{{ job.name}}/ipc-sizes.txt"{% endif %}
147
148
{#- gradle builds -#}
149
{%- elif "android" in job.name %}
+3
-3
.gitlab-ci/templates/include.win_containers.yml
+3
-3
.gitlab-ci/templates/include.win_containers.yml
···
1
# {#- included by .gitlab-ci.yml.jinja #}
2
# {#- SPDX-License-Identifier: CC0-1.0 #}
3
-
# {#- SPDX-FileCopyrightText: 2018-2022 Collabora, Ltd. and the Monado contributors #}
4
5
###
6
# Windows container-related jobs (prep and usage)
···
9
inherit:
10
default: false
11
variables:
12
-
MONADO_WIN_BASE_TAG: "20250418.0"
13
-
MONADO_WIN_MAIN_TAG: "20250418.0"
14
MONADO_BASE_IMAGE_PATH: "win2022/vs2022_base"
15
MONADO_MAIN_IMAGE_PATH: "win2022/vs2022"
16
···
1
# {#- included by .gitlab-ci.yml.jinja #}
2
# {#- SPDX-License-Identifier: CC0-1.0 #}
3
+
# {#- SPDX-FileCopyrightText: 2018-2025 Collabora, Ltd. and the Monado contributors #}
4
5
###
6
# Windows container-related jobs (prep and usage)
···
9
inherit:
10
default: false
11
variables:
12
+
MONADO_WIN_BASE_TAG: "20251127.3"
13
+
MONADO_WIN_MAIN_TAG: "20251127.3"
14
MONADO_BASE_IMAGE_PATH: "win2022/vs2022_base"
15
MONADO_MAIN_IMAGE_PATH: "win2022/vs2022"
16
+3
-3
.gitlab-ci/windows/monado_deps_build.ps1
+3
-3
.gitlab-ci/windows/monado_deps_build.ps1
···
1
# Copyright 2019-2022, Mesa contributors
2
-
# Copyright 2022, Collabora, Ltd.
3
# SPDX-License-Identifier: MIT
4
# Based on https://gitlab.freedesktop.org/mesa/mesa/-/blob/8396df5ad90aeb6ab2267811aba2187954562f81/.gitlab-ci/windows/mesa_deps_build.ps1
5
6
-
$VulkanRTVersion = "1.3.283.0"
7
8
# Download new TLS certs from Windows Update
9
Get-Date
···
28
Get-Date
29
Write-Host "Installing Vulkan runtime components"
30
$VulkanInstaller = "C:\VulkanRTInstaller.exe"
31
-
Invoke-WebRequest -Uri "https://sdk.lunarg.com/sdk/download/$VulkanRTVersion/windows/VulkanRT-$VulkanRTVersion-Installer.exe" -OutFile "$VulkanInstaller"
32
Start-Process -NoNewWindow -Wait "$VulkanInstaller" -ArgumentList "/S"
33
if (!$?) {
34
Write-Host "Failed to install Vulkan runtime components"
···
1
# Copyright 2019-2022, Mesa contributors
2
+
# Copyright 2022-2025, Collabora, Ltd.
3
# SPDX-License-Identifier: MIT
4
# Based on https://gitlab.freedesktop.org/mesa/mesa/-/blob/8396df5ad90aeb6ab2267811aba2187954562f81/.gitlab-ci/windows/mesa_deps_build.ps1
5
6
+
$VulkanRTVersion = "1.4.328.1"
7
8
# Download new TLS certs from Windows Update
9
Get-Date
···
28
Get-Date
29
Write-Host "Installing Vulkan runtime components"
30
$VulkanInstaller = "C:\VulkanRTInstaller.exe"
31
+
Invoke-WebRequest -Uri "https://sdk.lunarg.com/sdk/download/$VulkanRTVersion/windows/VulkanRT-X64-$VulkanRTVersion-Installer.exe" -OutFile "$VulkanInstaller"
32
Start-Process -NoNewWindow -Wait "$VulkanInstaller" -ArgumentList "/S"
33
if (!$?) {
34
Write-Host "Failed to install Vulkan runtime components"
+2
-2
.gitlab-ci/windows/monado_deps_vs2022.ps1
+2
-2
.gitlab-ci/windows/monado_deps_vs2022.ps1
···
1
# Copyright 2019-2022, Mesa contributors
2
-
# Copyright 2022, Collabora, Ltd.
3
# SPDX-License-Identifier: MIT
4
# Based on https://gitlab.freedesktop.org/mesa/mesa/-/blob/8396df5ad90aeb6ab2267811aba2187954562f81/.gitlab-ci/windows/mesa_deps_vs2019.ps1
5
···
29
"--add"
30
"Microsoft.VisualStudio.Component.Windows10SDK"
31
"--add"
32
-
"Microsoft.VisualStudio.Component.Windows11SDK.22000"
33
"--add"
34
"Component.Microsoft.Windows.CppWinRT"
35
"--add"
···
1
# Copyright 2019-2022, Mesa contributors
2
+
# Copyright 2022-2025, Collabora, Ltd.
3
# SPDX-License-Identifier: MIT
4
# Based on https://gitlab.freedesktop.org/mesa/mesa/-/blob/8396df5ad90aeb6ab2267811aba2187954562f81/.gitlab-ci/windows/mesa_deps_vs2019.ps1
5
···
29
"--add"
30
"Microsoft.VisualStudio.Component.Windows10SDK"
31
"--add"
32
+
"Microsoft.VisualStudio.Component.Windows11SDK.26100"
33
"--add"
34
"Component.Microsoft.Windows.CppWinRT"
35
"--add"
+4
-6
.gitlab-ci.yml
+4
-6
.gitlab-ci.yml
···
56
inherit:
57
default: false
58
variables:
59
-
MONADO_WIN_BASE_TAG: "20250418.0"
60
-
MONADO_WIN_MAIN_TAG: "20250418.0"
61
MONADO_BASE_IMAGE_PATH: "win2022/vs2022_base"
62
MONADO_MAIN_IMAGE_PATH: "win2022/vs2022"
63
···
369
370
- .gitlab-ci/prebuild.sh
371
- .gitlab-ci/ci-cmake-build.sh -DCMAKE_BUILD_TYPE=Debug -DXRT_HAVE_OPENCV=OFF
372
-
- src/xrt/ipc/shared/proto.py src/xrt/ipc/shared/proto.json structs.txt
373
- mkdir -p "debian:cmake-no-opencv"
374
-
- pahole --sizes --class_name file://structs.txt build/src/xrt/targets/openxr/libopenxr_monado.so > "debian:cmake-no-opencv/ipc-sizes.txt"
375
- cd build && ctest --output-on-failure
376
artifacts:
377
paths:
···
408
409
- .gitlab-ci/prebuild.sh
410
- .gitlab-ci/ci-cmake-build.sh -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=.gitlab-ci/i386.cmake -DXRT_HAVE_OPENCV=OFF
411
-
- src/xrt/ipc/shared/proto.py src/xrt/ipc/shared/proto.json structs.txt
412
- mkdir -p "debian:cmake:32bit"
413
-
- pahole --sizes --class_name file://structs.txt build/src/xrt/targets/openxr/libopenxr_monado.so > "debian:cmake:32bit/ipc-sizes.txt"
414
- cd build && ctest --output-on-failure
415
artifacts:
416
paths:
···
56
inherit:
57
default: false
58
variables:
59
+
MONADO_WIN_BASE_TAG: "20251127.3"
60
+
MONADO_WIN_MAIN_TAG: "20251127.3"
61
MONADO_BASE_IMAGE_PATH: "win2022/vs2022_base"
62
MONADO_MAIN_IMAGE_PATH: "win2022/vs2022"
63
···
369
370
- .gitlab-ci/prebuild.sh
371
- .gitlab-ci/ci-cmake-build.sh -DCMAKE_BUILD_TYPE=Debug -DXRT_HAVE_OPENCV=OFF
372
- mkdir -p "debian:cmake-no-opencv"
373
+
- pahole --sizes --class_name file://build/ipc-structs.txt build/src/xrt/targets/openxr/libopenxr_monado.so > "debian:cmake-no-opencv/ipc-sizes.txt"
374
- cd build && ctest --output-on-failure
375
artifacts:
376
paths:
···
407
408
- .gitlab-ci/prebuild.sh
409
- .gitlab-ci/ci-cmake-build.sh -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=.gitlab-ci/i386.cmake -DXRT_HAVE_OPENCV=OFF
410
- mkdir -p "debian:cmake:32bit"
411
+
- pahole --sizes --class_name file://build/ipc-structs.txt build/src/xrt/targets/openxr/libopenxr_monado.so > "debian:cmake:32bit/ipc-sizes.txt"
412
- cd build && ctest --output-on-failure
413
artifacts:
414
paths:
+2
CMakeLists.txt
+2
CMakeLists.txt
···
58
include(OptionWithDeps)
59
include(SPIR-V)
60
include(GNUInstallDirs)
61
if(NOT GIT_DESC)
62
include(GetGitRevisionDescription)
63
git_describe(GIT_DESC "--always")
···
367
option(XRT_FEATURE_OPENXR_ACTIVE_ACTION_SET_PRIORITY "Enable XR_EXT_active_action_set_priority" ON)
368
option(XRT_FEATURE_OPENXR_BODY_TRACKING_FB "Enable XR_FB_body_tracking" OFF)
369
option(XRT_FEATURE_OPENXR_DISPLAY_REFRESH_RATE "Enable XR_FB_display_refresh_rate" ON)
370
option(XRT_FEATURE_OPENXR_FACE_TRACKING2_FB "Enable XR_FB_face_tracking2" OFF)
371
option(XRT_FEATURE_OPENXR_FACIAL_TRACKING_HTC "Enable XR_HTC_facial_tracking" OFF)
372
option(XRT_FEATURE_OPENXR_FORCE_FEEDBACK_CURL "Enable XR_MNDX_force_feedback_curl" ON)
···
58
include(OptionWithDeps)
59
include(SPIR-V)
60
include(GNUInstallDirs)
61
+
include(MergeJSON)
62
if(NOT GIT_DESC)
63
include(GetGitRevisionDescription)
64
git_describe(GIT_DESC "--always")
···
368
option(XRT_FEATURE_OPENXR_ACTIVE_ACTION_SET_PRIORITY "Enable XR_EXT_active_action_set_priority" ON)
369
option(XRT_FEATURE_OPENXR_BODY_TRACKING_FB "Enable XR_FB_body_tracking" OFF)
370
option(XRT_FEATURE_OPENXR_DISPLAY_REFRESH_RATE "Enable XR_FB_display_refresh_rate" ON)
371
+
option(XRT_FEATURE_OPENXR_FACE_TRACKING_ANDROID "Enable XR_ANDROID_face_tracking" OFF)
372
option(XRT_FEATURE_OPENXR_FACE_TRACKING2_FB "Enable XR_FB_face_tracking2" OFF)
373
option(XRT_FEATURE_OPENXR_FACIAL_TRACKING_HTC "Enable XR_HTC_facial_tracking" OFF)
374
option(XRT_FEATURE_OPENXR_FORCE_FEEDBACK_CURL "Enable XR_MNDX_force_feedback_curl" ON)
+77
cmake/MergeJSON.cmake
+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
+2
-2
cmake/SPIR-V.cmake
···
14
function(spirv_shaders ret)
15
set(options)
16
set(oneValueArgs SPIRV_VERSION)
17
-
set(multiValueArgs SOURCES)
18
cmake_parse_arguments(_spirvshaders "${options}" "${oneValueArgs}"
19
"${multiValueArgs}" ${ARGN})
20
···
30
add_custom_command(
31
OUTPUT ${HEADER}
32
COMMAND ${GLSLANGVALIDATOR_COMMAND} -V --target-env spirv${_spirvshaders_SPIRV_VERSION} ${GLSL} --vn ${IDENTIFIER} -o ${HEADER}
33
-
DEPENDS ${GLSL})
34
list(APPEND HEADERS ${HEADER})
35
endforeach()
36
···
14
function(spirv_shaders ret)
15
set(options)
16
set(oneValueArgs SPIRV_VERSION)
17
+
set(multiValueArgs SOURCES DEPENDS)
18
cmake_parse_arguments(_spirvshaders "${options}" "${oneValueArgs}"
19
"${multiValueArgs}" ${ARGN})
20
···
30
add_custom_command(
31
OUTPUT ${HEADER}
32
COMMAND ${GLSLANGVALIDATOR_COMMAND} -V --target-env spirv${_spirvshaders_SPIRV_VERSION} ${GLSL} --vn ${IDENTIFIER} -o ${HEADER}
33
+
DEPENDS ${GLSL} ${_spirvshaders_DEPENDS})
34
list(APPEND HEADERS ${HEADER})
35
endforeach()
36
+139
cmake/merge_json.py
+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
-1
doc/changes/auxiliary/mr.2398.md
+1
doc/changes/auxiliary/mr.2613.md
+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
+2
doc/changes/compositor/mr.2596.md
+1
doc/changes/drivers/mr.2425.md
+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
doc/changes/ipc/mr.2644.md
···
···
1
+
Bump IPC_MAX_CLIENTS from 8 to 32.
+2
doc/changes/misc_features/mr.2605.md
+2
doc/changes/misc_features/mr.2605.md
+1
doc/changes/misc_fixes/mr.2579.md
+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
-1
doc/changes/state_trackers/mr.2399.md
+1
doc/changes/state_trackers/mr.2647.md
+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
+3
doc/changes/xrt/mr.2612.1.md
+4
doc/changes/xrt/mr.2612.2.md
+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
+3
doc/changes/xrt/mr.2612.3.md
+3
doc/changes/xrt/mr.2633.md
+3
doc/changes/xrt/mr.2633.md
+2
-1
scripts/generate_oxr_ext_support.py
+2
-1
scripts/generate_oxr_ext_support.py
···
76
['XR_EXT_samsung_odyssey_controller', 'XRT_FEATURE_OPENXR_INTERACTION_WINMR'],
77
['XR_EXT_user_presence', 'XRT_FEATURE_OPENXR_USER_PRESENCE'],
78
# Vendor extensions, sorted alphabetically.
79
['XR_BD_controller_interaction', 'XRT_FEATURE_OPENXR_INTERACTION_BYTEDANCE'],
80
['XR_FB_body_tracking', 'XRT_FEATURE_OPENXR_BODY_TRACKING_FB'],
81
['XR_FB_composition_layer_alpha_blend', 'XRT_FEATURE_OPENXR_LAYER_FB_ALPHA_BLEND'],
···
105
['XR_HTCX_vive_tracker_interaction', 'ALWAYS_DISABLED'],
106
['XR_MNDX_ball_on_a_stick_controller', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'],
107
['XR_MNDX_blubur_s1', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'],
108
-
['XR_MNDX_oculus_remote', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'],
109
['XR_MNDX_egl_enable', 'XR_USE_PLATFORM_EGL'],
110
['XR_MNDX_force_feedback_curl', 'XRT_FEATURE_OPENXR_FORCE_FEEDBACK_CURL'],
111
['XR_MNDX_hydra', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'],
112
['XR_MNDX_psvr2_interaction', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'],
113
['XR_MNDX_system_buttons', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'],
114
['XR_MNDX_xdev_space', 'XRT_FEATURE_OPENXR_XDEV_SPACE'],
···
76
['XR_EXT_samsung_odyssey_controller', 'XRT_FEATURE_OPENXR_INTERACTION_WINMR'],
77
['XR_EXT_user_presence', 'XRT_FEATURE_OPENXR_USER_PRESENCE'],
78
# Vendor extensions, sorted alphabetically.
79
+
['XR_ANDROID_face_tracking', 'XRT_FEATURE_OPENXR_FACE_TRACKING_ANDROID'],
80
['XR_BD_controller_interaction', 'XRT_FEATURE_OPENXR_INTERACTION_BYTEDANCE'],
81
['XR_FB_body_tracking', 'XRT_FEATURE_OPENXR_BODY_TRACKING_FB'],
82
['XR_FB_composition_layer_alpha_blend', 'XRT_FEATURE_OPENXR_LAYER_FB_ALPHA_BLEND'],
···
106
['XR_HTCX_vive_tracker_interaction', 'ALWAYS_DISABLED'],
107
['XR_MNDX_ball_on_a_stick_controller', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'],
108
['XR_MNDX_blubur_s1', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'],
109
['XR_MNDX_egl_enable', 'XR_USE_PLATFORM_EGL'],
110
['XR_MNDX_force_feedback_curl', 'XRT_FEATURE_OPENXR_FORCE_FEEDBACK_CURL'],
111
['XR_MNDX_hydra', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'],
112
+
['XR_MNDX_oculus_remote', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'],
113
['XR_MNDX_psvr2_interaction', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'],
114
['XR_MNDX_system_buttons', 'XRT_FEATURE_OPENXR_INTERACTION_MNDX'],
115
['XR_MNDX_xdev_space', 'XRT_FEATURE_OPENXR_XDEV_SPACE'],
+1
scripts/mapping.imp
+1
scripts/mapping.imp
···
40
{ symbol: ["XRT_FEATURE_OPENXR_BODY_TRACKING_FULL_BODY_META", "public", "\"xrt/xrt_config_build.h\"", "public"] },
41
{ symbol: ["XRT_FEATURE_OPENXR_DEBUG_UTILS", "public", "\"xrt/xrt_config_build.h\"", "public"] },
42
{ symbol: ["XRT_FEATURE_OPENXR_DISPLAY_REFRESH_RATE", "public", "\"xrt/xrt_config_build.h\"", "public"] },
43
{ symbol: ["XRT_FEATURE_OPENXR_FACE_TRACKING2_FB", "public", "\"xrt/xrt_config_build.h\"", "public"] },
44
{ symbol: ["XRT_FEATURE_OPENXR_FACIAL_TRACKING_HTC", "public", "\"xrt/xrt_config_build.h\"", "public"] },
45
{ symbol: ["XRT_FEATURE_OPENXR_FORCE_FEEDBACK_CURL", "public", "\"xrt/xrt_config_build.h\"", "public"] },
···
40
{ symbol: ["XRT_FEATURE_OPENXR_BODY_TRACKING_FULL_BODY_META", "public", "\"xrt/xrt_config_build.h\"", "public"] },
41
{ symbol: ["XRT_FEATURE_OPENXR_DEBUG_UTILS", "public", "\"xrt/xrt_config_build.h\"", "public"] },
42
{ symbol: ["XRT_FEATURE_OPENXR_DISPLAY_REFRESH_RATE", "public", "\"xrt/xrt_config_build.h\"", "public"] },
43
+
{ symbol: ["XRT_FEATURE_OPENXR_FACE_TRACKING_ANDROID", "public", "\"xrt/xrt_config_build.h\"", "public"] },
44
{ symbol: ["XRT_FEATURE_OPENXR_FACE_TRACKING2_FB", "public", "\"xrt/xrt_config_build.h\"", "public"] },
45
{ symbol: ["XRT_FEATURE_OPENXR_FACIAL_TRACKING_HTC", "public", "\"xrt/xrt_config_build.h\"", "public"] },
46
{ symbol: ["XRT_FEATURE_OPENXR_FORCE_FEEDBACK_CURL", "public", "\"xrt/xrt_config_build.h\"", "public"] },
-17
src/xrt/auxiliary/bindings/b_generated_bindings_helpers.c.template
-17
src/xrt/auxiliary/bindings/b_generated_bindings_helpers.c.template
···
14
15
// clang-format off
16
17
-
const char *
18
-
xrt_input_name_string(enum xrt_input_name input) {
19
-
switch(input)
20
-
{
21
-
$xrt_input_name_string_switch
22
-
}
23
-
}
24
-
25
enum xrt_input_name
26
xrt_input_name_enum(const char *input)
27
{
28
$xrt_input_name_enum_content
29
-
}
30
-
31
-
const char *
32
-
xrt_output_name_string(enum xrt_output_name output)
33
-
{
34
-
switch(output)
35
-
{
36
-
$xrt_output_name_string_switch
37
-
}
38
}
39
40
enum xrt_output_name
-6
src/xrt/auxiliary/bindings/b_generated_bindings_helpers.h
-6
src/xrt/auxiliary/bindings/b_generated_bindings_helpers.h
···
17
extern "C" {
18
#endif
19
20
-
const char *
21
-
xrt_input_name_string(enum xrt_input_name input);
22
-
23
enum xrt_input_name
24
xrt_input_name_enum(const char *input);
25
-
26
-
const char *
27
-
xrt_output_name_string(enum xrt_output_name output);
28
29
enum xrt_output_name
30
xrt_output_name_enum(const char *output);
-12
src/xrt/auxiliary/bindings/bindings.py
-12
src/xrt/auxiliary/bindings/bindings.py
···
588
inputs.add("XRT_INPUT_HT_CONFORMING_RIGHT")
589
inputs.add("XRT_INPUT_GENERIC_TRACKER_POSE")
590
591
-
xrt_input_name_string_switch = '\n'.join(
592
-
[(f'\tcase {input}: return "{input}";') for input in sorted(inputs)]
593
-
)
594
-
xrt_input_name_string_switch += (f'\n\tdefault: return "UNKNOWN";')
595
-
596
xrt_input_name_enum_content = '\n'.join(
597
[f'\tif(strcmp("{input}", input) == 0) return {input};' for input in sorted(inputs)]
598
)
599
xrt_input_name_enum_content += f'\n\treturn XRT_INPUT_GENERIC_TRACKER_POSE;'
600
601
-
xrt_output_name_string_switch = '\n'.join(
602
-
[(f'\tcase {output}: return "{output}";') for output in sorted(outputs)]
603
-
)
604
-
xrt_output_name_string_switch+= f'\n\tdefault: return "UNKNOWN";'
605
-
606
xrt_output_name_enum_content = '\n'.join(
607
[f'\tif(strcmp("{output}", output) == 0) return {output};' for output in sorted(outputs)]
608
)
···
614
615
with open(file, "w") as f:
616
filled = src.substitute(
617
-
xrt_input_name_string_switch=xrt_input_name_string_switch,
618
xrt_input_name_enum_content=xrt_input_name_enum_content,
619
-
xrt_output_name_string_switch=xrt_output_name_string_switch,
620
xrt_output_name_enum_content=xrt_output_name_enum_content
621
)
622
f.write(filled)
···
588
inputs.add("XRT_INPUT_HT_CONFORMING_RIGHT")
589
inputs.add("XRT_INPUT_GENERIC_TRACKER_POSE")
590
591
xrt_input_name_enum_content = '\n'.join(
592
[f'\tif(strcmp("{input}", input) == 0) return {input};' for input in sorted(inputs)]
593
)
594
xrt_input_name_enum_content += f'\n\treturn XRT_INPUT_GENERIC_TRACKER_POSE;'
595
596
xrt_output_name_enum_content = '\n'.join(
597
[f'\tif(strcmp("{output}", output) == 0) return {output};' for output in sorted(outputs)]
598
)
···
604
605
with open(file, "w") as f:
606
filled = src.substitute(
607
xrt_input_name_enum_content=xrt_input_name_enum_content,
608
xrt_output_name_enum_content=xrt_output_name_enum_content
609
)
610
f.write(filled)
-1
src/xrt/auxiliary/d3d/d3d_d3d12_allocator.hpp
-1
src/xrt/auxiliary/d3d/d3d_d3d12_allocator.hpp
···
31
* @param xsci Swapchain create info: note that the format is assumed to be a DXGI_FORMAT (conversion to typeless is
32
* automatic)
33
* @param image_count The number of images to create.
34
-
* @param keyed_mutex Whether to create images with a shared "keyed mutex" as well
35
* @param[out] out_images A vector that will be cleared and populated with the images.
36
* @param[out] out_handles A vector that will be cleared and populated with the corresponding native handles.
37
* @param[out] out_image_mem_size The image memory allocation size in bytes
···
31
* @param xsci Swapchain create info: note that the format is assumed to be a DXGI_FORMAT (conversion to typeless is
32
* automatic)
33
* @param image_count The number of images to create.
34
* @param[out] out_images A vector that will be cleared and populated with the images.
35
* @param[out] out_handles A vector that will be cleared and populated with the corresponding native handles.
36
* @param[out] out_image_mem_size The image memory allocation size in bytes
+21
src/xrt/auxiliary/math/m_api.h
+21
src/xrt/auxiliary/math/m_api.h
···
18
19
#include "xrt/xrt_defines.h"
20
21
+
#include "math/m_mathinclude.h"
22
+
23
#ifdef __cplusplus
24
extern "C" {
25
#endif
···
76
* @ingroup aux_math
77
*/
78
#define CLAMP(X, A, B) (MIN(MAX((X), (A)), (B)))
79
+
80
+
/*!
81
+
* Degrees to radians conversion.
82
+
*
83
+
* @ingroup aux_math
84
+
*/
85
+
// clang-format off
86
+
// @todo: Remove the clang-format off/on when we move to a newer clang-format in CI.
87
+
#define DEG_TO_RAD(DEG) ((DEG) * M_PI / 180.)
88
+
// clang-format on
89
+
90
+
/*!
91
+
* Radians to degrees conversion.
92
+
*
93
+
* @ingroup aux_math
94
+
*/
95
+
// clang-format off
96
+
#define RAD_TO_DEG(RAD) ((RAD) * 180.0 / M_PI)
97
+
// clang-format on
98
99
100
/*
+37
-33
src/xrt/auxiliary/math/m_relation_history.cpp
+37
-33
src/xrt/auxiliary/math/m_relation_history.cpp
···
183
}
184
}
185
186
-
bool
187
-
m_relation_history_estimate_motion(struct m_relation_history *rh,
188
-
const struct xrt_space_relation *in_relation,
189
-
int64_t timestamp,
190
-
struct xrt_space_relation *out_relation)
191
{
192
193
-
int64_t last_time_ns;
194
-
struct xrt_space_relation last_relation;
195
-
if (!m_relation_history_get_latest(rh, &last_time_ns, &last_relation)) {
196
-
return false;
197
-
};
198
199
-
float dt = (float)time_ns_to_s(timestamp - last_time_ns);
200
201
-
// Used to find out what values are valid in both the old relation and the new relation
202
-
enum xrt_space_relation_flags tmp_flags =
203
-
(enum xrt_space_relation_flags)(last_relation.relation_flags & in_relation->relation_flags);
204
-
205
-
// Brevity
206
-
enum xrt_space_relation_flags &outf = out_relation->relation_flags;
207
-
208
-
209
-
if (tmp_flags & XRT_SPACE_RELATION_POSITION_VALID_BIT) {
210
-
outf = (enum xrt_space_relation_flags)(outf | XRT_SPACE_RELATION_POSITION_VALID_BIT);
211
-
outf = (enum xrt_space_relation_flags)(outf | XRT_SPACE_RELATION_POSITION_TRACKED_BIT);
212
213
-
outf = (enum xrt_space_relation_flags)(outf | XRT_SPACE_RELATION_LINEAR_VELOCITY_VALID_BIT);
214
215
-
out_relation->linear_velocity = (in_relation->pose.position - last_relation.pose.position) / dt;
216
}
217
218
-
if (tmp_flags & XRT_SPACE_RELATION_ORIENTATION_VALID_BIT) {
219
-
outf = (enum xrt_space_relation_flags)(outf | XRT_SPACE_RELATION_ORIENTATION_VALID_BIT);
220
-
outf = (enum xrt_space_relation_flags)(outf | XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT);
221
222
-
outf = (enum xrt_space_relation_flags)(outf | XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT);
223
224
-
math_quat_finite_difference(&last_relation.pose.orientation, &in_relation->pose.orientation, dt,
225
-
&out_relation->angular_velocity);
226
}
227
228
-
out_relation->pose = in_relation->pose;
229
-
230
-
return true;
231
}
232
233
bool
···
183
}
184
}
185
186
+
static void
187
+
m_relation_history_estimate_motion(struct xrt_space_relation const &old_relation,
188
+
struct xrt_space_relation const &new_relation,
189
+
float dt,
190
+
struct xrt_vec3 &out_linear_velocity,
191
+
struct xrt_vec3 &out_angular_velocity,
192
+
enum xrt_space_relation_flags &out_flags)
193
{
194
+
assert(dt != 0.0f);
195
196
+
enum xrt_space_relation_flags shared_flags =
197
+
(enum xrt_space_relation_flags)(old_relation.relation_flags & new_relation.relation_flags);
198
199
+
// If both relations have position data, estimate linear velocity
200
+
if (shared_flags & XRT_SPACE_RELATION_POSITION_VALID_BIT) {
201
+
out_flags = (enum xrt_space_relation_flags)(out_flags | XRT_SPACE_RELATION_LINEAR_VELOCITY_VALID_BIT);
202
203
+
out_linear_velocity = (new_relation.pose.position - old_relation.pose.position) / dt;
204
+
}
205
206
+
// If both relations have orientation data, estimate angular velocity
207
+
if (shared_flags & XRT_SPACE_RELATION_ORIENTATION_VALID_BIT) {
208
+
out_flags = (enum xrt_space_relation_flags)(out_flags | XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT);
209
210
+
math_quat_finite_difference(&old_relation.pose.orientation, &new_relation.pose.orientation, dt,
211
+
&out_angular_velocity);
212
}
213
+
}
214
+
215
+
bool
216
+
m_relation_history_push_with_motion_estimation(struct m_relation_history *rh,
217
+
struct xrt_space_relation const *in_relation,
218
+
int64_t timestamp)
219
+
{
220
+
assert((in_relation->relation_flags & XRT_SPACE_RELATION_LINEAR_VELOCITY_VALID_BIT) == 0);
221
+
assert((in_relation->relation_flags & XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT) == 0);
222
223
+
struct xrt_space_relation final_relation = *in_relation;
224
225
+
int64_t last_time_ns;
226
+
struct xrt_space_relation last_relation;
227
+
if (m_relation_history_get_latest(rh, &last_time_ns, &last_relation) && timestamp > last_time_ns) {
228
+
float dt = (float)time_ns_to_s(timestamp - last_time_ns);
229
230
+
m_relation_history_estimate_motion(last_relation, *in_relation, dt, final_relation.linear_velocity,
231
+
final_relation.angular_velocity, final_relation.relation_flags);
232
}
233
234
+
return m_relation_history_push(rh, &final_relation, timestamp);
235
}
236
237
bool
+15
-17
src/xrt/auxiliary/math/m_relation_history.h
+15
-17
src/xrt/auxiliary/math/m_relation_history.h
···
63
m_relation_history_push(struct m_relation_history *rh, struct xrt_space_relation const *in_relation, int64_t timestamp);
64
65
/*!
66
-
* Interpolates or extrapolates to the desired timestamp.
67
*
68
-
* Read-only operation - doesn't remove anything from the buffer or anything like that - you can call this as often as
69
-
* you want.
70
*
71
* @public @memberof m_relation_history
72
*/
73
-
enum m_relation_history_result
74
-
m_relation_history_get(const struct m_relation_history *rh,
75
-
int64_t at_timestamp_ns,
76
-
struct xrt_space_relation *out_relation);
77
78
/*!
79
-
* Estimates the movement (velocity and angular velocity) of a new relation based on
80
-
* the latest relation found in the buffer (as returned by m_relation_history_get_latest).
81
*
82
-
* Read-only on m_relation_history and in_relation.
83
-
* Copies in_relation->pose to out_relation->pose, and writes new flags and linear/angular velocities to
84
-
* out_relation->pose. OK to alias in_relation and out_relation.
85
*
86
* @public @memberof m_relation_history
87
*/
88
-
bool
89
-
m_relation_history_estimate_motion(struct m_relation_history *rh,
90
-
const struct xrt_space_relation *in_relation,
91
-
int64_t timestamp,
92
-
struct xrt_space_relation *out_relation);
93
94
/*!
95
* Get the latest report in the buffer, if any.
···
63
m_relation_history_push(struct m_relation_history *rh, struct xrt_space_relation const *in_relation, int64_t timestamp);
64
65
/*!
66
+
* Pushes a new pose to the history, estimating linear and angular velocity based on the previous entry.
67
*
68
+
* If the history is full, it will also pop a pose out of the other side of the buffer.
69
+
*
70
+
* @return false if the timestamp is earlier than the most recent timestamp already recorded
71
*
72
* @public @memberof m_relation_history
73
*/
74
+
bool
75
+
m_relation_history_push_with_motion_estimation(struct m_relation_history *rh,
76
+
struct xrt_space_relation const *in_relation,
77
+
int64_t timestamp);
78
79
/*!
80
+
* Interpolates or extrapolates to the desired timestamp.
81
*
82
+
* Read-only operation - doesn't remove anything from the buffer or anything like that - you can call this as often
83
+
* as you want.
84
*
85
* @public @memberof m_relation_history
86
*/
87
+
enum m_relation_history_result
88
+
m_relation_history_get(const struct m_relation_history *rh,
89
+
int64_t at_timestamp_ns,
90
+
struct xrt_space_relation *out_relation);
91
92
/*!
93
* Get the latest report in the buffer, if any.
+4
-4
src/xrt/auxiliary/tracking/t_tracker_slam.cpp
+4
-4
src/xrt/auxiliary/tracking/t_tracker_slam.cpp
···
407
{
408
t.timing.enabled = false;
409
410
-
u_var_add_ro_ftext(&t, "\n%s", "Tracker timing");
411
412
// Setup toggle button
413
static const char *msg[2] = {"[OFF] Enable timing", "[ON] Disable timing"};
···
527
{
528
t.features.enabled = false;
529
530
-
u_var_add_ro_ftext(&t, "\n%s", "Tracker features");
531
532
// Setup toggle button
533
static const char *msg[2] = {"[OFF] Enable features info", "[ON] Disable features info"};
···
695
static void
696
gt_ui_setup(TrackerSlam &t)
697
{
698
-
u_var_add_ro_ftext(&t, "\n%s", "Tracker groundtruth");
699
t.gt.diff_ui.values.data = t.gt.diffs_mm;
700
t.gt.diff_ui.values.length = UI_GTDIFF_POSE_COUNT;
701
t.gt.diff_ui.values.index_ptr = &t.gt.diff_idx;
···
1081
}
1082
1083
u_var_add_gui_header(&t, NULL, "Stats");
1084
-
u_var_add_ro_ftext(&t, "\n%s", "Record to CSV files");
1085
u_var_add_bool(&t, &t.slam_traj_writer->enabled, "Record tracked trajectory");
1086
u_var_add_bool(&t, &t.pred_traj_writer->enabled, "Record predicted trajectory");
1087
u_var_add_bool(&t, &t.filt_traj_writer->enabled, "Record filtered trajectory");
···
407
{
408
t.timing.enabled = false;
409
410
+
u_var_add_ro_raw_text(&t, "\nTracker timing", "Tracker timing");
411
412
// Setup toggle button
413
static const char *msg[2] = {"[OFF] Enable timing", "[ON] Disable timing"};
···
527
{
528
t.features.enabled = false;
529
530
+
u_var_add_ro_raw_text(&t, "\nTracker features", "Tracker features");
531
532
// Setup toggle button
533
static const char *msg[2] = {"[OFF] Enable features info", "[ON] Disable features info"};
···
695
static void
696
gt_ui_setup(TrackerSlam &t)
697
{
698
+
u_var_add_ro_raw_text(&t, "\nTracker groundtruth", "Tracker groundtruth");
699
t.gt.diff_ui.values.data = t.gt.diffs_mm;
700
t.gt.diff_ui.values.length = UI_GTDIFF_POSE_COUNT;
701
t.gt.diff_ui.values.index_ptr = &t.gt.diff_idx;
···
1081
}
1082
1083
u_var_add_gui_header(&t, NULL, "Stats");
1084
+
u_var_add_ro_raw_text(&t, "\nRecord to CSV files", "Record to CSV files");
1085
u_var_add_bool(&t, &t.slam_traj_writer->enabled, "Record tracked trajectory");
1086
u_var_add_bool(&t, &t.pred_traj_writer->enabled, "Record predicted trajectory");
1087
u_var_add_bool(&t, &t.filt_traj_writer->enabled, "Record filtered trajectory");
+2
src/xrt/auxiliary/util/CMakeLists.txt
+2
src/xrt/auxiliary/util/CMakeLists.txt
+2
-1
src/xrt/auxiliary/util/u_config_json.c
+2
-1
src/xrt/auxiliary/util/u_config_json.c
···
14
#include "util/u_file.h"
15
#include "util/u_json.h"
16
#include "util/u_debug.h"
17
18
#include "u_config_json.h"
19
···
504
505
cJSON_AddItemToObject(entry, "offset", make_pose(&overrides[i].offset));
506
507
-
const char *input_name_string = xrt_input_name_string(overrides[i].input_name);
508
cJSON_AddStringToObject(entry, "xrt_input_name", input_name_string);
509
510
cJSON_AddItemToArray(o, entry);
···
14
#include "util/u_file.h"
15
#include "util/u_json.h"
16
#include "util/u_debug.h"
17
+
#include "util/u_pretty_print.h"
18
19
#include "u_config_json.h"
20
···
505
506
cJSON_AddItemToObject(entry, "offset", make_pose(&overrides[i].offset));
507
508
+
const char *input_name_string = u_str_xrt_input_name(overrides[i].input_name);
509
cJSON_AddStringToObject(entry, "xrt_input_name", input_name_string);
510
511
cJSON_AddItemToArray(o, entry);
+51
-58
src/xrt/auxiliary/util/u_device.c
+51
-58
src/xrt/auxiliary/util/u_device.c
···
11
*/
12
13
#include "util/u_device.h"
14
#include "util/u_logging.h"
15
#include "util/u_misc.h"
16
#include "util/u_visibility_mask.h"
···
461
u_device_get_view_poses(struct xrt_device *xdev,
462
const struct xrt_vec3 *default_eye_relation,
463
int64_t at_timestamp_ns,
464
uint32_t view_count,
465
struct xrt_space_relation *out_head_relation,
466
struct xrt_fov *out_fovs,
···
510
511
/*
512
*
513
-
* Not implemented function helpers.
514
*
515
*/
516
517
-
#define E(FN) U_LOG_E("Function " #FN " is not implemented for '%s'", xdev->str)
518
-
519
-
xrt_result_t
520
-
u_device_ni_get_hand_tracking(struct xrt_device *xdev,
521
-
enum xrt_input_name name,
522
-
int64_t desired_timestamp_ns,
523
-
struct xrt_hand_joint_set *out_value,
524
-
int64_t *out_timestamp_ns)
525
{
526
-
E(get_hand_tracking);
527
-
return XRT_ERROR_NOT_IMPLEMENTED;
528
-
}
529
530
-
xrt_result_t
531
-
u_device_ni_set_output(struct xrt_device *xdev, enum xrt_output_name name, const struct xrt_output_value *value)
532
-
{
533
-
E(set_output);
534
-
return XRT_ERROR_NOT_IMPLEMENTED;
535
-
}
536
537
-
xrt_result_t
538
-
u_device_ni_get_view_poses(struct xrt_device *xdev,
539
-
const struct xrt_vec3 *default_eye_relation,
540
-
int64_t at_timestamp_ns,
541
-
uint32_t view_count,
542
-
struct xrt_space_relation *out_head_relation,
543
-
struct xrt_fov *out_fovs,
544
-
struct xrt_pose *out_poses)
545
-
{
546
-
E(get_view_poses);
547
-
return XRT_ERROR_NOT_IMPLEMENTED;
548
-
}
549
-
550
-
xrt_result_t
551
-
u_device_ni_compute_distortion(
552
-
struct xrt_device *xdev, uint32_t view, float u, float v, struct xrt_uv_triplet *out_result)
553
-
{
554
-
E(compute_distortion);
555
-
return XRT_ERROR_NOT_IMPLEMENTED;
556
-
}
557
558
-
xrt_result_t
559
-
u_device_ni_get_visibility_mask(struct xrt_device *xdev,
560
-
enum xrt_visibility_mask_type type,
561
-
uint32_t view_index,
562
-
struct xrt_visibility_mask **out_mask)
563
-
{
564
-
E(get_visibility_mask);
565
-
return XRT_ERROR_NOT_IMPLEMENTED;
566
-
}
567
568
-
bool
569
-
u_device_ni_is_form_factor_available(struct xrt_device *xdev, enum xrt_form_factor form_factor)
570
-
{
571
-
E(is_form_factor_available);
572
-
return false;
573
-
}
574
575
-
xrt_result_t
576
-
u_device_ni_get_battery_status(struct xrt_device *xdev, bool *out_present, bool *out_charging, float *out_charge)
577
-
{
578
-
E(get_battery_status);
579
-
return XRT_ERROR_NOT_IMPLEMENTED;
580
}
···
11
*/
12
13
#include "util/u_device.h"
14
+
#include "util/u_device_ni.h"
15
#include "util/u_logging.h"
16
#include "util/u_misc.h"
17
#include "util/u_visibility_mask.h"
···
462
u_device_get_view_poses(struct xrt_device *xdev,
463
const struct xrt_vec3 *default_eye_relation,
464
int64_t at_timestamp_ns,
465
+
enum xrt_view_type view_type,
466
uint32_t view_count,
467
struct xrt_space_relation *out_head_relation,
468
struct xrt_fov *out_fovs,
···
512
513
/*
514
*
515
+
* Helper function to fill in defaults.
516
*
517
*/
518
519
+
void
520
+
u_device_populate_function_pointers(struct xrt_device *xdev,
521
+
u_device_get_tracked_pose_function_t get_tracked_pose_fn,
522
+
u_device_destroy_function_t destroy_fn)
523
{
524
+
if (get_tracked_pose_fn == NULL) {
525
+
U_LOG_E("Got get_tracked_pose_fn == NULL!");
526
+
assert(get_tracked_pose_fn != NULL);
527
+
}
528
529
+
if (destroy_fn == NULL) {
530
+
U_LOG_E("Got destroy_fn == NULL!");
531
+
assert(destroy_fn != NULL);
532
+
}
533
534
+
/*
535
+
* This must be implemented by the xrt_device, but not necessarily by
536
+
* the driver so use noop version.
537
+
*/
538
+
xdev->update_inputs = u_device_noop_update_inputs;
539
540
+
// This must be implemented by the driver.
541
+
xdev->get_tracked_pose = get_tracked_pose_fn;
542
543
+
/*
544
+
* These are not required to be implemented by the xrt_device, so use
545
+
* not implemented versions, and let the driver override if needed.
546
+
*/
547
+
xdev->get_hand_tracking = u_device_ni_get_hand_tracking;
548
+
xdev->get_face_tracking = u_device_ni_get_face_tracking;
549
+
xdev->get_body_skeleton = u_device_ni_get_body_skeleton;
550
+
xdev->get_body_joints = u_device_ni_get_body_joints;
551
+
xdev->reset_body_tracking_calibration_meta = u_device_ni_reset_body_tracking_calibration_meta;
552
+
xdev->set_body_tracking_calibration_override_meta = u_device_ni_set_body_tracking_calibration_override_meta;
553
+
xdev->set_output = u_device_ni_set_output;
554
+
xdev->get_output_limits = u_device_ni_get_output_limits;
555
+
xdev->get_presence = u_device_ni_get_presence;
556
+
xdev->begin_plane_detection_ext = u_device_ni_begin_plane_detection_ext;
557
+
xdev->destroy_plane_detection_ext = u_device_ni_destroy_plane_detection_ext;
558
+
xdev->get_plane_detection_state_ext = u_device_ni_get_plane_detection_state_ext;
559
+
xdev->get_plane_detections_ext = u_device_ni_get_plane_detections_ext;
560
+
xdev->get_view_poses = u_device_ni_get_view_poses;
561
+
xdev->compute_distortion = u_device_ni_compute_distortion;
562
+
xdev->get_visibility_mask = u_device_ni_get_visibility_mask;
563
+
xdev->ref_space_usage = u_device_ni_ref_space_usage;
564
+
xdev->is_form_factor_available = u_device_ni_is_form_factor_available;
565
+
xdev->get_battery_status = u_device_ni_get_battery_status;
566
+
xdev->get_brightness = u_device_ni_get_brightness;
567
+
xdev->set_brightness = u_device_ni_set_brightness;
568
+
xdev->begin_feature = u_device_ni_begin_feature;
569
+
xdev->end_feature = u_device_ni_end_feature;
570
571
+
// This must be implemented by the driver.
572
+
xdev->destroy = destroy_fn;
573
}
+22
-56
src/xrt/auxiliary/util/u_device.h
+22
-56
src/xrt/auxiliary/util/u_device.h
···
171
u_device_get_view_poses(struct xrt_device *xdev,
172
const struct xrt_vec3 *default_eye_relation,
173
int64_t at_timestamp_ns,
174
uint32_t view_count,
175
struct xrt_space_relation *out_head_relation,
176
struct xrt_fov *out_fovs,
···
205
206
/*
207
*
208
-
* Not implemented function helpers.
209
*
210
*/
211
212
/*!
213
-
* Not implemented function for @ref xrt_device::get_hand_tracking.
214
-
*
215
-
* @ingroup aux_util
216
-
*/
217
-
xrt_result_t
218
-
u_device_ni_get_hand_tracking(struct xrt_device *xdev,
219
-
enum xrt_input_name name,
220
-
int64_t desired_timestamp_ns,
221
-
struct xrt_hand_joint_set *out_value,
222
-
int64_t *out_timestamp_ns);
223
-
224
-
/*!
225
-
* Not implemented function for @ref xrt_device::set_output.
226
-
*
227
-
* @ingroup aux_util
228
-
*/
229
-
xrt_result_t
230
-
u_device_ni_set_output(struct xrt_device *xdev, enum xrt_output_name name, const struct xrt_output_value *value);
231
-
232
-
/*!
233
-
* Not implemented function for @ref xrt_device::get_view_poses.
234
-
*
235
-
* @ingroup aux_util
236
-
*/
237
-
xrt_result_t
238
-
u_device_ni_get_view_poses(struct xrt_device *xdev,
239
-
const struct xrt_vec3 *default_eye_relation,
240
-
int64_t at_timestamp_ns,
241
-
uint32_t view_count,
242
-
struct xrt_space_relation *out_head_relation,
243
-
struct xrt_fov *out_fovs,
244
-
struct xrt_pose *out_poses);
245
-
246
-
/*!
247
-
* Not implemented function for @ref xrt_device::compute_distortion.
248
*
249
* @ingroup aux_util
250
*/
251
-
xrt_result_t
252
-
u_device_ni_compute_distortion(
253
-
struct xrt_device *xdev, uint32_t view, float u, float v, struct xrt_uv_triplet *out_result);
254
255
/*!
256
-
* Not implemented function for @ref xrt_device::get_visibility_mask.
257
*
258
* @ingroup aux_util
259
*/
260
-
xrt_result_t
261
-
u_device_ni_get_visibility_mask(struct xrt_device *xdev,
262
-
enum xrt_visibility_mask_type type,
263
-
uint32_t view_index,
264
-
struct xrt_visibility_mask **out_mask);
265
266
/*!
267
-
* Not implemented function for @ref xrt_device::is_form_factor_available.
268
*
269
-
* @ingroup aux_util
270
-
*/
271
-
bool
272
-
u_device_ni_is_form_factor_available(struct xrt_device *xdev, enum xrt_form_factor form_factor);
273
-
274
-
/*!
275
-
* Not implemented function for @ref xrt_device::get_battery_status.
276
*
277
* @ingroup aux_util
278
*/
279
-
xrt_result_t
280
-
u_device_ni_get_battery_status(struct xrt_device *xdev, bool *out_present, bool *out_charging, float *out_charge);
281
-
282
283
#ifdef __cplusplus
284
}
···
171
u_device_get_view_poses(struct xrt_device *xdev,
172
const struct xrt_vec3 *default_eye_relation,
173
int64_t at_timestamp_ns,
174
+
enum xrt_view_type view_type,
175
uint32_t view_count,
176
struct xrt_space_relation *out_head_relation,
177
struct xrt_fov *out_fovs,
···
206
207
/*
208
*
209
+
* Helper function to fill in defaults.
210
*
211
*/
212
213
/*!
214
+
* Function pointer type for the device's get_tracked_pose function.
215
*
216
* @ingroup aux_util
217
*/
218
+
typedef xrt_result_t (*u_device_get_tracked_pose_function_t)(struct xrt_device *xdev,
219
+
const enum xrt_input_name name,
220
+
const int64_t at_timestamp_ns,
221
+
struct xrt_space_relation *const out_relation);
222
223
/*!
224
+
* Function pointer type for the device's destroy function.
225
*
226
* @ingroup aux_util
227
*/
228
+
typedef void (*u_device_destroy_function_t)(struct xrt_device *xdev);
229
230
/*!
231
+
* Populate the device's function pointers with default implementations.
232
*
233
+
* This function fills in all device function pointers with either noop or
234
+
* not-implemented versions, allowing drivers to override only the functions
235
+
* they actually implement. The exceptions are get_tracked_pose and destroy,
236
+
* which must be implemented by the driver and are passed in as function
237
+
* pointers, these must not be NULL.
238
*
239
+
* @param[in,out] xdev The device to populate with default function pointers.
240
+
* @param[in] get_tracked_pose_fn The function pointer to the device's get_tracked_pose function.
241
+
* @param[in] destroy_fn The function pointer to the device's destroy function.
242
* @ingroup aux_util
243
*/
244
+
void
245
+
u_device_populate_function_pointers(struct xrt_device *xdev,
246
+
u_device_get_tracked_pose_function_t get_tracked_pose_fn,
247
+
u_device_destroy_function_t destroy_fn);
248
249
#ifdef __cplusplus
250
}
+217
src/xrt/auxiliary/util/u_device_ni.c
+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
+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
-2
src/xrt/auxiliary/util/u_hand_simulation.c
-2
src/xrt/auxiliary/util/u_hand_tracking.c
-2
src/xrt/auxiliary/util/u_hand_tracking.c
+61
-2
src/xrt/auxiliary/util/u_logging.c
+61
-2
src/xrt/auxiliary/util/u_logging.c
···
1
// Copyright 2019-2025, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
74
75
/*
76
*
77
* Logging sink.
78
*
79
*/
···
294
int ret = 0;
295
296
#ifdef XRT_FEATURE_COLOR_LOG
297
-
if (isatty(STDERR_FILENO)) {
298
ret = print_prefix_color(func, level, buf, remaining);
299
} else {
300
ret = print_prefix_mono(func, level, buf, remaining);
···
407
OutputDebugStringA(storage);
408
#endif
409
410
-
fwrite(storage, printed, 1, stderr);
411
412
#else
413
#error "Port needed for logging function"
···
454
u_log(file, line, calling_fn, level, "%s", sink.buffer);
455
}
456
457
void
458
u_log(const char *file, int line, const char *func, enum u_logging_level level, const char *format, ...)
459
{
460
va_list args;
461
va_start(args, format);
462
DISPATCH_SINK(file, line, func, level, format, args);
463
do_print(file, line, func, level, format, args);
···
474
...)
475
{
476
va_list args;
477
va_start(args, format);
478
DISPATCH_SINK(file, line, func, level, format, args);
479
do_print(file, line, func, level, format, args);
···
1
// Copyright 2019-2025, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
75
76
/*
77
*
78
+
* Logging file code.
79
+
*
80
+
*/
81
+
82
+
static FILE *g_log_file = NULL;
83
+
84
+
void
85
+
u_log_set_output_file(const char *filename)
86
+
{
87
+
// While not thread safe, this function is externally synchronized.
88
+
if (g_log_file != NULL) {
89
+
FILE *tmp = g_log_file;
90
+
g_log_file = NULL;
91
+
92
+
fflush(tmp);
93
+
fclose(tmp);
94
+
tmp = NULL;
95
+
}
96
+
97
+
if (filename == NULL) {
98
+
return; // Turning off file logging.
99
+
}
100
+
101
+
g_log_file = fopen(filename, "w");
102
+
if (g_log_file == NULL) {
103
+
U_LOG_E("Failed to open '%s'", filename);
104
+
}
105
+
}
106
+
107
+
108
+
/*
109
+
*
110
* Logging sink.
111
*
112
*/
···
327
int ret = 0;
328
329
#ifdef XRT_FEATURE_COLOR_LOG
330
+
if (g_log_file == NULL && isatty(STDERR_FILENO)) {
331
ret = print_prefix_color(func, level, buf, remaining);
332
} else {
333
ret = print_prefix_mono(func, level, buf, remaining);
···
440
OutputDebugStringA(storage);
441
#endif
442
443
+
FILE *output = g_log_file != NULL ? g_log_file : stderr;
444
+
fwrite(storage, printed, 1, output);
445
+
446
+
#if defined(XRT_OS_WINDOWS)
447
+
/*
448
+
* Windows like to buffer messages, call flush here to make sure all
449
+
* logs gets written out in case of sudden exits and crashes.
450
+
*/
451
+
fflush(output);
452
+
#endif
453
454
#else
455
#error "Port needed for logging function"
···
496
u_log(file, line, calling_fn, level, "%s", sink.buffer);
497
}
498
499
+
static u_log_filter_func_t g_filter = NULL;
500
+
501
+
void
502
+
u_log_set_filter(u_log_filter_func_t filter)
503
+
{
504
+
g_filter = filter;
505
+
}
506
+
507
void
508
u_log(const char *file, int line, const char *func, enum u_logging_level level, const char *format, ...)
509
{
510
va_list args;
511
+
// Check filter first
512
+
if (g_filter != NULL && !g_filter(file, line, func, level)) {
513
+
return; // Skip this message
514
+
}
515
+
516
va_start(args, format);
517
DISPATCH_SINK(file, line, func, level, format, args);
518
do_print(file, line, func, level, format, args);
···
529
...)
530
{
531
va_list args;
532
+
// Check filter first
533
+
if (g_filter != NULL && !g_filter(file, line, func, level)) {
534
+
return; // Skip this message
535
+
}
536
va_start(args, format);
537
DISPATCH_SINK(file, line, func, level, format, args);
538
do_print(file, line, func, level, format, args);
+32
src/xrt/auxiliary/util/u_logging.h
+32
src/xrt/auxiliary/util/u_logging.h
···
1
// Copyright 2020-2025, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
68
const char *format,
69
va_list args,
70
void *data);
71
72
/*!
73
* For places where you really want printf, prints a new-line.
···
270
u_log_get_global_level(void);
271
272
/*!
273
* @brief Main non-device-related log implementation function: do not call directly, use a macro that wraps it.
274
*
275
* This function always logs: level is used for printing or passed to native logging functions.
···
377
const char *calling_fn,
378
xrt_result_t xret,
379
const char *called_fn);
380
381
/*!
382
* @}
···
1
// Copyright 2020-2025, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
69
const char *format,
70
va_list args,
71
void *data);
72
+
73
+
/*!
74
+
* Function typedef for filtering log messages.
75
+
*
76
+
* @param file Source file name associated with a message.
77
+
* @param line Source file line associated with a message.
78
+
* @param func Function name associated with a message.
79
+
* @param level Message level: used for formatting or forwarding to native log functions.
80
+
* @return true if message should be logged, false to filter it out.
81
+
*/
82
+
typedef bool (*u_log_filter_func_t)(const char *file, int line, const char *func, enum u_logging_level level);
83
84
/*!
85
* For places where you really want printf, prints a new-line.
···
282
u_log_get_global_level(void);
283
284
/*!
285
+
* Sets the output file for the logging instead of stderr, this function is
286
+
* externally synchronized with ALL other logging functions. Which means do not
287
+
* call any other logging function from different threads during a call to this
288
+
* function. Also to avoid leaks call this function with NULL to close the
289
+
* internally managed FILE object.
290
+
*
291
+
* WANRING THIS FUNCTION IS EXTERNALLY SYNCHRONIZED WITH ALL OTHER FUNCTIONS.
292
+
*/
293
+
void
294
+
u_log_set_output_file(const char *filename);
295
+
296
+
/*!
297
* @brief Main non-device-related log implementation function: do not call directly, use a macro that wraps it.
298
*
299
* This function always logs: level is used for printing or passed to native logging functions.
···
401
const char *calling_fn,
402
xrt_result_t xret,
403
const char *called_fn);
404
+
405
+
/*!
406
+
* @brief Add function to set the filter
407
+
*
408
+
* @param filter Filter function to set
409
+
*/
410
+
void
411
+
u_log_set_filter(u_log_filter_func_t filter);
412
413
/*!
414
* @}
+86
-52
src/xrt/auxiliary/util/u_pretty_print.c
+86
-52
src/xrt/auxiliary/util/u_pretty_print.c
···
1
// Copyright 2022-2024, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
39
case XRT_INPUT_TYPE_HAND_TRACKING: return "HAND_TRACKING";
40
case XRT_INPUT_TYPE_FACE_TRACKING: return "FACE_TRACKING";
41
case XRT_INPUT_TYPE_BODY_TRACKING: return "BODY_TRACKING";
42
-
default: return "<UNKNOWN>";
43
}
44
}
45
46
void
···
70
71
/*
72
*
73
* 'Exported' functions.
74
*
75
*/
···
112
void
113
u_pp_xrt_input_name(struct u_pp_delegate dg, enum xrt_input_name name)
114
{
115
-
#define XRT_INPUT_LIST_TO_CASE(NAME, _) \
116
-
case NAME: DG(#NAME); return;
117
-
118
-
switch (name) {
119
-
XRT_INPUT_LIST(XRT_INPUT_LIST_TO_CASE)
120
}
121
122
-
#undef XRT_INPUT_LIST_TO_CASE
123
-
124
/*
125
-
* No default case so we get warnings of missing entries.
126
* Invalid values handled below.
127
*/
128
···
136
void
137
u_pp_xrt_output_name(struct u_pp_delegate dg, enum xrt_output_name name)
138
{
139
-
#define XRT_OUTPUT_CASE(NAME) \
140
-
case NAME: DG(#NAME); return
141
142
-
switch (name) {
143
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_SIMPLE_VIBRATION);
144
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_PSMV_RUMBLE_VIBRATION);
145
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_INDEX_HAPTIC);
146
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_VIVE_HAPTIC);
147
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_WMR_HAPTIC);
148
149
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_XBOX_HAPTIC_LEFT);
150
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_XBOX_HAPTIC_RIGHT);
151
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_XBOX_HAPTIC_LEFT_TRIGGER);
152
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_XBOX_HAPTIC_RIGHT_TRIGGER);
153
154
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_TOUCH_HAPTIC);
155
-
156
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_FORCE_FEEDBACK_LEFT);
157
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_FORCE_FEEDBACK_RIGHT);
158
-
159
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_G2_CONTROLLER_HAPTIC);
160
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_ODYSSEY_CONTROLLER_HAPTIC);
161
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_ML2_CONTROLLER_VIBRATION);
162
-
163
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_PSSENSE_VIBRATION);
164
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_PSSENSE_TRIGGER_FEEDBACK);
165
-
166
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_VIVE_TRACKER_HAPTIC);
167
-
168
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_OPPO_MR_HAPTIC);
169
-
170
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_PICO_NEO3_HAPTIC);
171
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_PICO4_HAPTIC);
172
-
173
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_VIVE_COSMOS_HAPTIC);
174
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_VIVE_FOCUS3_HAPTIC);
175
-
176
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_TOUCH_PRO_HAPTIC);
177
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_TOUCH_PRO_HAPTIC_TRIGGER);
178
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_TOUCH_PRO_HAPTIC_THUMB);
179
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_TOUCH_PLUS_HAPTIC);
180
-
181
-
XRT_OUTPUT_CASE(XRT_OUTPUT_NAME_PSVR2_HAPTIC);
182
-
}
183
-
184
-
#undef XRT_OUTPUT_CASE
185
}
186
187
void
···
234
case XRT_OPERATION_CANCELLED: DG("XRT_OPERATION_CANCELLED"); return;
235
case XRT_ERROR_FUTURE_RESULT_NOT_READY: DG("XRT_ERROR_FUTURE_RESULT_NOT_READY"); return;
236
case XRT_ERROR_FUTURE_ALREADY_COMPLETE: DG("XRT_ERROR_FUTURE_ALREADY_COMPLETE"); return;
237
}
238
// clang-format on
239
···
1
// Copyright 2022-2024, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
40
case XRT_INPUT_TYPE_HAND_TRACKING: return "HAND_TRACKING";
41
case XRT_INPUT_TYPE_FACE_TRACKING: return "FACE_TRACKING";
42
case XRT_INPUT_TYPE_BODY_TRACKING: return "BODY_TRACKING";
43
}
44
+
45
+
return "<UNKNOWN>";
46
+
}
47
+
48
+
const char *
49
+
get_xrt_output_type_short_str(enum xrt_output_type type)
50
+
{
51
+
switch (type) {
52
+
case XRT_OUTPUT_TYPE_VIBRATION: return "XRT_OUTPUT_TYPE_VIBRATION";
53
+
case XRT_OUTPUT_TYPE_FORCE_FEEDBACK: return "XRT_OUTPUT_TYPE_FORCE_FEEDBACK";
54
+
}
55
+
56
+
return "<UNKNOWN>";
57
}
58
59
void
···
83
84
/*
85
*
86
+
* 'Exported' str functions.
87
+
*
88
+
*/
89
+
90
+
const char *
91
+
u_str_xrt_input_name_or_null(enum xrt_input_name name)
92
+
{
93
+
#define XRT_INPUT_LIST_TO_CASE(NAME, _) \
94
+
case NAME: return #NAME;
95
+
96
+
// No default case so we get warnings of missing entries.
97
+
switch (name) {
98
+
XRT_INPUT_LIST(XRT_INPUT_LIST_TO_CASE)
99
+
}
100
+
101
+
#undef XRT_INPUT_LIST_TO_CASE
102
+
103
+
return NULL;
104
+
}
105
+
106
+
const char *
107
+
u_str_xrt_output_name_or_null(enum xrt_output_name name)
108
+
{
109
+
#define XRT_OUTPUT_LIST_TO_CASE(NAME, _) \
110
+
case NAME: return #NAME;
111
+
112
+
// No default case so we get warnings of missing entries.
113
+
switch (name) {
114
+
XRT_OUTPUT_LIST(XRT_OUTPUT_LIST_TO_CASE)
115
+
}
116
+
117
+
#undef XRT_OUTPUT_LIST_TO_CASE
118
+
119
+
return NULL;
120
+
}
121
+
122
+
const char *
123
+
u_str_xrt_device_name_or_null(enum xrt_device_name name)
124
+
{
125
+
#define XRT_DEVICE_NAME_LIST_TO_CASE(NAME) \
126
+
case NAME: return #NAME;
127
+
128
+
// No default case so we get warnings of missing entries.
129
+
switch (name) {
130
+
XRT_DEVICE_NAME_LIST(XRT_DEVICE_NAME_LIST_TO_CASE)
131
+
}
132
+
133
+
#undef XRT_DEVICE_NAME_LIST_TO_CASE
134
+
135
+
return NULL;
136
+
}
137
+
138
+
139
+
/*
140
+
*
141
* 'Exported' functions.
142
*
143
*/
···
180
void
181
u_pp_xrt_input_name(struct u_pp_delegate dg, enum xrt_input_name name)
182
{
183
+
const char *might_be_null = u_str_xrt_input_name_or_null(name);
184
+
if (might_be_null != NULL) {
185
+
DG(might_be_null);
186
+
return;
187
}
188
189
/*
190
* Invalid values handled below.
191
*/
192
···
200
void
201
u_pp_xrt_output_name(struct u_pp_delegate dg, enum xrt_output_name name)
202
{
203
+
const char *might_be_null = u_str_xrt_output_name_or_null(name);
204
+
if (might_be_null != NULL) {
205
+
DG(might_be_null);
206
+
return;
207
+
}
208
209
+
/*
210
+
* Invalid values handled below.
211
+
*/
212
213
+
uint32_t id = XRT_GET_OUTPUT_ID(name);
214
+
enum xrt_output_type type = XRT_GET_OUTPUT_TYPE(name);
215
+
const char *str = get_xrt_output_type_short_str(type);
216
217
+
u_pp(dg, "XRT_OUTPUT_0x%04x_%s", id, str);
218
}
219
220
void
···
267
case XRT_OPERATION_CANCELLED: DG("XRT_OPERATION_CANCELLED"); return;
268
case XRT_ERROR_FUTURE_RESULT_NOT_READY: DG("XRT_ERROR_FUTURE_RESULT_NOT_READY"); return;
269
case XRT_ERROR_FUTURE_ALREADY_COMPLETE: DG("XRT_ERROR_FUTURE_ALREADY_COMPLETE"); return;
270
+
case XRT_ERROR_DEVICE_NOT_ATTACHABLE: DG("XRT_ERROR_DEVICE_NOT_ATTACHABLE"); return;
271
}
272
// clang-format on
273
+43
src/xrt/auxiliary/util/u_pretty_print.h
+43
src/xrt/auxiliary/util/u_pretty_print.h
···
29
* they can easily be chained together to form a debug message printing out
30
* various information. Most of the final logging functions in Monado inserts a
31
* newline at the end of the message and we don't want two to be inserted.
32
*/
33
34
/*!
35
* Function prototype for receiving pretty printed strings.
···
29
* they can easily be chained together to form a debug message printing out
30
* various information. Most of the final logging functions in Monado inserts a
31
* newline at the end of the message and we don't want two to be inserted.
32
+
*
33
+
* There are also helpers that goes from an enum to a string that that doesn't
34
+
* use the delegate to do the printing, these returns string that are compiled
35
+
* into the binary. They will return 'UNKNOWN' if they don't know the value.
36
+
* But can be made to return NULL on unknown.
37
*/
38
+
39
+
/*!
40
+
* Returns a string of the input name, or NULL if invalid.
41
+
*
42
+
* @ingroup aux_pretty
43
+
*/
44
+
const char *
45
+
u_str_xrt_input_name_or_null(enum xrt_input_name name);
46
+
47
+
/*!
48
+
* Returns a string of the output name, or NULL if invalid.
49
+
*
50
+
* @ingroup aux_pretty
51
+
*/
52
+
const char *
53
+
u_str_xrt_output_name_or_null(enum xrt_output_name name);
54
+
55
+
/*!
56
+
* Returns a string of the device name, or NULL if invalid.
57
+
*
58
+
* @ingroup aux_pretty
59
+
*/
60
+
const char *
61
+
u_str_xrt_device_name_or_null(enum xrt_device_name name);
62
+
63
+
#define U_STR_NO_NULL(NAME, TYPE) \
64
+
static inline const char *NAME(TYPE enumerate) \
65
+
{ \
66
+
const char *str = NAME##_or_null(enumerate); \
67
+
return str != NULL ? str : "UNKNOWN"; \
68
+
}
69
+
70
+
U_STR_NO_NULL(u_str_xrt_input_name, enum xrt_input_name)
71
+
U_STR_NO_NULL(u_str_xrt_output_name, enum xrt_output_name)
72
+
U_STR_NO_NULL(u_str_xrt_device_name, enum xrt_device_name)
73
+
74
+
#undef U_STR_NO_NULL
75
+
76
77
/*!
78
* Function prototype for receiving pretty printed strings.
+1
-1
src/xrt/auxiliary/util/u_sink_converter.c
+1
-1
src/xrt/auxiliary/util/u_sink_converter.c
+132
-18
src/xrt/auxiliary/util/u_space_overseer.c
+132
-18
src/xrt/auxiliary/util/u_space_overseer.c
···
1
// Copyright 2023, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
42
U_SPACE_TYPE_POSE,
43
U_SPACE_TYPE_OFFSET,
44
U_SPACE_TYPE_ROOT,
45
};
46
47
/*!
···
330
m_relation_chain_push_relation(xrc, &xsr);
331
} break;
332
case U_SPACE_TYPE_OFFSET: m_relation_chain_push_pose_if_not_identity(xrc, &space->offset.pose); break;
333
-
case U_SPACE_TYPE_ROOT: return; // Stops the traversing.
334
}
335
336
// Please tail-call optimise this miss compiler.
···
352
case U_SPACE_TYPE_NULL: break;
353
case U_SPACE_TYPE_POSE: break;
354
case U_SPACE_TYPE_OFFSET: break;
355
-
case U_SPACE_TYPE_ROOT: return; // Stops the traversing.
356
}
357
358
// Can't tail-call optimise this one :(
···
371
} break;
372
case U_SPACE_TYPE_OFFSET: m_relation_chain_push_inverted_pose_if_not_identity(xrc, &space->offset.pose); break;
373
case U_SPACE_TYPE_ROOT: assert(false); // Should not get here.
374
}
375
}
376
···
469
470
// Created with one reference.
471
uso->base.semantic.root = &us->base;
472
}
473
474
···
1033
return xret;
1034
}
1035
1036
static void
1037
destroy(struct xrt_space_overseer *xso)
1038
{
···
1089
uso->base.set_tracking_origin_offset = set_tracking_origin_offset;
1090
uso->base.get_reference_space_offset = get_reference_space_offset;
1091
uso->base.set_reference_space_offset = set_reference_space_offset;
1092
uso->base.destroy = destroy;
1093
uso->broadcast = broadcast;
1094
···
1117
bool root_is_unbounded,
1118
bool per_app_local_spaces)
1119
{
1120
-
struct xrt_space *root = uso->base.semantic.root; // Convenience
1121
uso->per_app_local_spaces = per_app_local_spaces;
1122
1123
for (uint32_t i = 0; i < xdev_count; i++) {
1124
-
struct xrt_device *xdev = xdevs[i];
1125
-
struct xrt_tracking_origin *torig = xdev->tracking_origin;
1126
-
uint64_t key = (uint64_t)(intptr_t)torig;
1127
-
struct xrt_space *xs = NULL;
1128
-
1129
-
void *ptr = NULL;
1130
-
u_hashmap_int_find(uso->xto_map, key, &ptr);
1131
-
1132
-
if (ptr != NULL) {
1133
-
xs = (struct xrt_space *)ptr;
1134
-
} else {
1135
-
u_space_overseer_create_offset_space(uso, root, &torig->initial_offset, &xs);
1136
-
u_hashmap_int_insert(uso->xto_map, key, xs);
1137
}
1138
-
1139
-
u_space_overseer_link_space_to_device(uso, xs, xdev);
1140
}
1141
1142
// If these are set something is probably wrong, but just in case unset them.
···
1
// Copyright 2023, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
43
U_SPACE_TYPE_POSE,
44
U_SPACE_TYPE_OFFSET,
45
U_SPACE_TYPE_ROOT,
46
+
47
+
/*!
48
+
* Space designed to be attachable to others, most importantly it is
49
+
* re-attachable, and in order to move all of the spaces that has this
50
+
* space as it's parent/next we need a node that can be updated.
51
+
*/
52
+
U_SPACE_TYPE_ATTACHABLE,
53
};
54
55
/*!
···
338
m_relation_chain_push_relation(xrc, &xsr);
339
} break;
340
case U_SPACE_TYPE_OFFSET: m_relation_chain_push_pose_if_not_identity(xrc, &space->offset.pose); break;
341
+
case U_SPACE_TYPE_ROOT: return; // Stops the traversing.
342
+
case U_SPACE_TYPE_ATTACHABLE: break; // No-op
343
}
344
345
// Please tail-call optimise this miss compiler.
···
361
case U_SPACE_TYPE_NULL: break;
362
case U_SPACE_TYPE_POSE: break;
363
case U_SPACE_TYPE_OFFSET: break;
364
+
case U_SPACE_TYPE_ROOT: return; // Stops the traversing.
365
+
case U_SPACE_TYPE_ATTACHABLE: break; // No-op
366
}
367
368
// Can't tail-call optimise this one :(
···
381
} break;
382
case U_SPACE_TYPE_OFFSET: m_relation_chain_push_inverted_pose_if_not_identity(xrc, &space->offset.pose); break;
383
case U_SPACE_TYPE_ROOT: assert(false); // Should not get here.
384
+
case U_SPACE_TYPE_ATTACHABLE: break; // No-op
385
}
386
}
387
···
480
481
// Created with one reference.
482
uso->base.semantic.root = &us->base;
483
+
}
484
+
485
+
486
+
/*
487
+
*
488
+
* Device helpers.
489
+
*
490
+
*/
491
+
492
+
/*!
493
+
* Helper function to add a device to the space overseer. This function
494
+
* handles creating or finding a space for the device's tracking origin
495
+
* and linking the device to that space.
496
+
*/
497
+
static xrt_result_t
498
+
add_device_helper(struct u_space_overseer *uso, struct xrt_device *xdev)
499
+
{
500
+
struct xrt_tracking_origin *torig = xdev->tracking_origin;
501
+
assert(torig != NULL);
502
+
503
+
struct xrt_space *root = uso->base.semantic.root;
504
+
uint64_t key = (uint64_t)(intptr_t)torig;
505
+
struct xrt_space *xs = NULL;
506
+
507
+
// Need to take the write lock.
508
+
pthread_rwlock_wrlock(&uso->lock);
509
+
510
+
// Does this tracking origin already have space.
511
+
void *ptr = NULL;
512
+
u_hashmap_int_find(uso->xto_map, key, &ptr);
513
+
514
+
if (ptr != NULL) {
515
+
xs = (struct xrt_space *)ptr;
516
+
} else if (torig->type == XRT_TRACKING_TYPE_ATTACHABLE) {
517
+
/*
518
+
* If we ever make u_space_overseer sub-classable make sure
519
+
* this calls the right function, can't call interface function
520
+
* as the lock is held here.
521
+
*/
522
+
xs = (struct xrt_space *)create_space(U_SPACE_TYPE_ATTACHABLE, u_space(root));
523
+
u_hashmap_int_insert(uso->xto_map, key, xs);
524
+
} else {
525
+
/*
526
+
* If we ever make u_space_overseer sub-classable make sure
527
+
* this calls the right function, can't call interface function
528
+
* as the lock is held here.
529
+
*/
530
+
xs = (struct xrt_space *)create_space(U_SPACE_TYPE_OFFSET, u_space(root));
531
+
532
+
update_offset_write_locked(u_space(xs), &torig->initial_offset);
533
+
534
+
u_hashmap_int_insert(uso->xto_map, key, xs);
535
+
}
536
+
537
+
pthread_rwlock_unlock(&uso->lock);
538
+
539
+
u_space_overseer_link_space_to_device(uso, xs, xdev);
540
+
541
+
return XRT_SUCCESS;
542
}
543
544
···
1103
return xret;
1104
}
1105
1106
+
static xrt_result_t
1107
+
add_device(struct xrt_space_overseer *xso, struct xrt_device *xdev)
1108
+
{
1109
+
struct u_space_overseer *uso = u_space_overseer(xso);
1110
+
1111
+
return add_device_helper(uso, xdev);
1112
+
}
1113
+
1114
+
static xrt_result_t
1115
+
attach_device(struct xrt_space_overseer *xso, struct xrt_device *xdev, struct xrt_space *space)
1116
+
{
1117
+
struct u_space_overseer *uso = u_space_overseer(xso);
1118
+
1119
+
// Check that the device has the correct tracking origin type.
1120
+
if (xdev->tracking_origin == NULL || xdev->tracking_origin->type != XRT_TRACKING_TYPE_ATTACHABLE) {
1121
+
U_LOG_E("Device '%s' does not have XRT_TRACKING_TYPE_ATTACHABLE tracking origin type", xdev->str);
1122
+
return XRT_ERROR_DEVICE_NOT_ATTACHABLE;
1123
+
}
1124
+
1125
+
// If no space is provided, use the root space.
1126
+
struct xrt_space *target_space = space;
1127
+
if (target_space == NULL) {
1128
+
target_space = uso->base.semantic.root;
1129
+
}
1130
+
1131
+
xrt_result_t xret = XRT_SUCCESS;
1132
+
pthread_rwlock_wrlock(&uso->lock);
1133
+
1134
+
1135
+
void *ptr = NULL;
1136
+
uint64_t key = (uint64_t)(intptr_t)xdev->tracking_origin;
1137
+
u_hashmap_int_find(uso->xto_map, key, &ptr);
1138
+
if (ptr == NULL) {
1139
+
U_LOG_E("Device doesn't have space associated with it!");
1140
+
xret = XRT_ERROR_DEVICE_NOT_ATTACHABLE;
1141
+
goto err_unlock;
1142
+
}
1143
+
1144
+
struct u_space *us = (struct u_space *)ptr;
1145
+
if (us->type != U_SPACE_TYPE_ATTACHABLE) {
1146
+
U_LOG_E("Device doesn't have a attachable space!");
1147
+
xret = XRT_ERROR_DEVICE_NOT_ATTACHABLE;
1148
+
goto err_unlock;
1149
+
}
1150
+
1151
+
// Update the link.
1152
+
u_space_reference(&us->next, u_space(target_space));
1153
+
1154
+
err_unlock:
1155
+
pthread_rwlock_unlock(&uso->lock);
1156
+
1157
+
return xret;
1158
+
}
1159
+
1160
static void
1161
destroy(struct xrt_space_overseer *xso)
1162
{
···
1213
uso->base.set_tracking_origin_offset = set_tracking_origin_offset;
1214
uso->base.get_reference_space_offset = get_reference_space_offset;
1215
uso->base.set_reference_space_offset = set_reference_space_offset;
1216
+
uso->base.add_device = add_device;
1217
+
uso->base.attach_device = attach_device;
1218
uso->base.destroy = destroy;
1219
uso->broadcast = broadcast;
1220
···
1243
bool root_is_unbounded,
1244
bool per_app_local_spaces)
1245
{
1246
uso->per_app_local_spaces = per_app_local_spaces;
1247
1248
+
// Add all devices to the space overseer.
1249
for (uint32_t i = 0; i < xdev_count; i++) {
1250
+
xrt_result_t xret = add_device_helper(uso, xdevs[i]);
1251
+
if (xret != XRT_SUCCESS) {
1252
+
U_LOG_E("Failed to add device '%s' to space overseer!", xdevs[i]->str);
1253
}
1254
}
1255
1256
// If these are set something is probably wrong, but just in case unset them.
+12
-2
src/xrt/auxiliary/util/u_var.h
+12
-2
src/xrt/auxiliary/util/u_var.h
···
1
// Copyright 2019-2024, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
83
//! Pointer that will be passed to the function as its only argument
84
void *ptr;
85
86
//! Button text, use var `name` if zeroed
87
char label[64];
88
···
229
U_VAR_KIND_NATIVE_IMAGES_DEBUG,
230
U_VAR_KIND_LOG_LEVEL,
231
U_VAR_KIND_RO_TEXT,
232
-
U_VAR_KIND_RO_FTEXT,
233
U_VAR_KIND_RO_I16,
234
U_VAR_KIND_RO_I32,
235
U_VAR_KIND_RO_U16,
···
247
U_VAR_KIND_GUI_HEADER,
248
U_VAR_KIND_GUI_HEADER_BEGIN,
249
U_VAR_KIND_GUI_HEADER_END,
250
U_VAR_KIND_BUTTON,
251
U_VAR_KIND_COMBO,
252
U_VAR_KIND_HISTOGRAM_F32,
···
389
ADD_FUNC(native_images_debug, struct u_native_images_debug, NATIVE_IMAGES_DEBUG) \
390
ADD_FUNC(log_level, enum u_logging_level, LOG_LEVEL) \
391
ADD_FUNC(ro_text, const char, RO_TEXT) \
392
-
ADD_FUNC(ro_ftext, const char, RO_FTEXT) \
393
ADD_FUNC(ro_i16, int16_t, RO_I16) \
394
ADD_FUNC(ro_i32, int32_t, RO_I32) \
395
ADD_FUNC(ro_u16, uint16_t, RO_U16) \
···
407
ADD_FUNC(gui_header, bool, GUI_HEADER) \
408
ADD_FUNC(gui_header_begin, bool, GUI_HEADER_BEGIN) \
409
ADD_FUNC(gui_header_end, bool, GUI_HEADER_END) \
410
ADD_FUNC(button, struct u_var_button, BUTTON) \
411
ADD_FUNC(combo, struct u_var_combo, COMBO) \
412
ADD_FUNC(draggable_f32, struct u_var_draggable_f32, DRAGGABLE_F32) \
···
1
// Copyright 2019-2024, Collabora, Ltd.
2
+
// Copyright 2024-2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
84
//! Pointer that will be passed to the function as its only argument
85
void *ptr;
86
87
+
/*!
88
+
* Is the pointer pressing down on the button curruently, this is not
89
+
* edge triggered like the callback. For a mouse this means that the
90
+
* pointer is hovering the button and the left is held down.
91
+
*/
92
+
xrt_atomic_s32_t downed;
93
+
94
//! Button text, use var `name` if zeroed
95
char label[64];
96
···
237
U_VAR_KIND_NATIVE_IMAGES_DEBUG,
238
U_VAR_KIND_LOG_LEVEL,
239
U_VAR_KIND_RO_TEXT,
240
+
U_VAR_KIND_RO_RAW_TEXT,
241
U_VAR_KIND_RO_I16,
242
U_VAR_KIND_RO_I32,
243
U_VAR_KIND_RO_U16,
···
255
U_VAR_KIND_GUI_HEADER,
256
U_VAR_KIND_GUI_HEADER_BEGIN,
257
U_VAR_KIND_GUI_HEADER_END,
258
+
U_VAR_KIND_GUI_SAMELINE,
259
U_VAR_KIND_BUTTON,
260
U_VAR_KIND_COMBO,
261
U_VAR_KIND_HISTOGRAM_F32,
···
398
ADD_FUNC(native_images_debug, struct u_native_images_debug, NATIVE_IMAGES_DEBUG) \
399
ADD_FUNC(log_level, enum u_logging_level, LOG_LEVEL) \
400
ADD_FUNC(ro_text, const char, RO_TEXT) \
401
+
ADD_FUNC(ro_raw_text, const char, RO_RAW_TEXT) \
402
ADD_FUNC(ro_i16, int16_t, RO_I16) \
403
ADD_FUNC(ro_i32, int32_t, RO_I32) \
404
ADD_FUNC(ro_u16, uint16_t, RO_U16) \
···
416
ADD_FUNC(gui_header, bool, GUI_HEADER) \
417
ADD_FUNC(gui_header_begin, bool, GUI_HEADER_BEGIN) \
418
ADD_FUNC(gui_header_end, bool, GUI_HEADER_END) \
419
+
ADD_FUNC(gui_sameline, void, GUI_SAMELINE) \
420
ADD_FUNC(button, struct u_var_button, BUTTON) \
421
ADD_FUNC(combo, struct u_var_combo, COMBO) \
422
ADD_FUNC(draggable_f32, struct u_var_draggable_f32, DRAGGABLE_F32) \
+52
-17
src/xrt/auxiliary/util/u_worker.c
+52
-17
src/xrt/auxiliary/util/u_worker.c
···
1
// Copyright 2022, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
94
//! Pointer to poll of threads.
95
struct u_worker_thread_pool *uwtp;
96
97
-
//! Number of tasks that is pending or being worked on in this group.
98
-
size_t current_submitted_tasks_count;
99
100
-
//! Number of threads that have been released or newly entered wait.
101
size_t released_count;
102
103
struct
···
143
continue;
144
}
145
146
-
*out_task = p->tasks[i];
147
p->tasks[i] = (struct task){NULL, NULL, NULL};
148
p->tasks_in_array_count--;
149
return;
150
}
151
···
164
165
p->tasks[i] = (struct task){g, func, data};
166
p->tasks_in_array_count++;
167
-
g->current_submitted_tasks_count++;
168
return;
169
}
170
···
201
*/
202
203
static bool
204
-
locked_group_should_enter_wait_loop(struct pool *p, struct group *g)
205
{
206
-
if (g->current_submitted_tasks_count == 0) {
207
return false;
208
}
209
210
-
// Enter the loop as a released thread.
211
-
g->released_count++;
212
-
213
return true;
214
}
215
···
237
*/
238
239
// Tasks available.
240
-
if (g->current_submitted_tasks_count > 0) {
241
242
// We have been released or newly entered the loop.
243
if (g->released_count > 0) {
···
265
locked_group_wake_waiter_if_allowed(struct pool *p, struct group *g)
266
{
267
// Are there still outstanding tasks?
268
-
if (g->current_submitted_tasks_count > 0) {
269
return;
270
}
271
···
343
344
snprintf(t->name, sizeof(t->name), "%s: Worker", p->prefix);
345
U_TRACE_SET_THREAD_NAME(t->name);
346
347
os_mutex_lock(&p->mutex);
348
···
373
// No longer working.
374
p->working_count--;
375
376
-
// Only now decrement the task count on the owning group.
377
-
task.g->current_submitted_tasks_count--;
378
379
// Wake up any waiter.
380
locked_group_wake_waiter_if_allowed(p, task.g);
···
401
XRT_TRACE_MARKER();
402
int ret;
403
404
-
assert(starting_worker_count < thread_count);
405
-
if (starting_worker_count >= thread_count) {
406
return NULL;
407
}
408
···
532
os_mutex_lock(&p->mutex);
533
534
// Can we early out?
535
-
if (!locked_group_should_enter_wait_loop(p, g)) {
536
os_mutex_unlock(&p->mutex);
537
return;
538
}
539
540
// Wait here until all work been started and completed.
541
while (locked_group_should_wait(p, g)) {
···
1
// Copyright 2022, Collabora, Ltd.
2
+
// Copyright 2024-2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
95
//! Pointer to poll of threads.
96
struct u_worker_thread_pool *uwtp;
97
98
+
/*!
99
+
* The number of tasks that are pending execution by a worker.
100
+
* They reside in the pool::tasks array.
101
+
*/
102
+
uint32_t current_tasks_in_array;
103
+
104
+
/*!
105
+
* Number of tasks that are being worked on.
106
+
* They live inside of the working thread.
107
+
*/
108
+
uint32_t current_working_tasks;
109
110
+
/*!
111
+
* Number of waiting threads that have been released by a worker,
112
+
* or a thread that has started waiting (see u_worker_group_wait_all).
113
+
*/
114
size_t released_count;
115
116
struct
···
156
continue;
157
}
158
159
+
struct task task = p->tasks[i];
160
p->tasks[i] = (struct task){NULL, NULL, NULL};
161
+
162
p->tasks_in_array_count--;
163
+
task.g->current_tasks_in_array--;
164
+
task.g->current_working_tasks++;
165
+
166
+
*out_task = task;
167
+
168
return;
169
}
170
···
183
184
p->tasks[i] = (struct task){g, func, data};
185
p->tasks_in_array_count++;
186
+
g->current_tasks_in_array++;
187
return;
188
}
189
···
220
*/
221
222
static bool
223
+
locked_group_has_tasks_waiting_or_inflight(const struct group *g)
224
{
225
+
if (g->current_tasks_in_array == 0 && g->current_working_tasks == 0) {
226
return false;
227
}
228
229
return true;
230
}
231
···
253
*/
254
255
// Tasks available.
256
+
if (locked_group_has_tasks_waiting_or_inflight(g)) {
257
258
// We have been released or newly entered the loop.
259
if (g->released_count > 0) {
···
281
locked_group_wake_waiter_if_allowed(struct pool *p, struct group *g)
282
{
283
// Are there still outstanding tasks?
284
+
if (locked_group_has_tasks_waiting_or_inflight(g)) {
285
return;
286
}
287
···
359
360
snprintf(t->name, sizeof(t->name), "%s: Worker", p->prefix);
361
U_TRACE_SET_THREAD_NAME(t->name);
362
+
os_thread_name(&t->thread, t->name);
363
364
os_mutex_lock(&p->mutex);
365
···
390
// No longer working.
391
p->working_count--;
392
393
+
// We are no longer working on the task.
394
+
task.g->current_working_tasks--;
395
+
396
+
// This must hold true.
397
+
assert(task.g->current_tasks_in_array <= p->tasks_in_array_count);
398
399
// Wake up any waiter.
400
locked_group_wake_waiter_if_allowed(p, task.g);
···
421
XRT_TRACE_MARKER();
422
int ret;
423
424
+
assert(starting_worker_count <= thread_count);
425
+
if (starting_worker_count > thread_count) {
426
return NULL;
427
}
428
···
552
os_mutex_lock(&p->mutex);
553
554
// Can we early out?
555
+
if (!locked_group_has_tasks_waiting_or_inflight(g)) {
556
os_mutex_unlock(&p->mutex);
557
return;
558
}
559
+
560
+
/*
561
+
* The released_count is tied to the decrement of worker_limit, that is
562
+
* when a waiting thread is woken up the worker_limit is decreased, and
563
+
* released_count is increased. The waiting thread will then double
564
+
* check that it can be released or not, if it can not be released it
565
+
* will once again donate this thread and increase the worker_limit.
566
+
*
567
+
* If it can be released it will decrement released_count and exit the
568
+
* loop below.
569
+
*
570
+
* So if we increment it here, the loop will increase worker_limit
571
+
* which is what we want.
572
+
*/
573
+
g->released_count++;
574
575
// Wait here until all work been started and completed.
576
while (locked_group_should_wait(p, g)) {
+12
src/xrt/auxiliary/util/u_worker.hpp
+12
src/xrt/auxiliary/util/u_worker.hpp
···
1
// Copyright 2022, Collabora, Ltd.
2
+
// Copyright 2024-2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
104
~SharedThreadGroup()
105
{
106
u_worker_group_reference(&mGroup, nullptr);
107
+
}
108
+
109
+
/*!
110
+
* In-general it's recommended to use the TaskCollection helper,
111
+
* but some use cases requires direct access to the push function,
112
+
* so it's provided here.
113
+
*/
114
+
void
115
+
push(u_worker_group_func_t f, void *data)
116
+
{
117
+
u_worker_group_push(mGroup, f, data);
118
}
119
120
friend TaskCollection;
-2
src/xrt/auxiliary/vive/vive_poses.c
-2
src/xrt/auxiliary/vive/vive_poses.c
+41
-35
src/xrt/auxiliary/vk/vk_bundle_init.c
+41
-35
src/xrt/auxiliary/vk/vk_bundle_init.c
···
241
242
vk->features.timestamp_compute_and_graphics = pdp.limits.timestampComputeAndGraphics;
243
vk->features.timestamp_period = pdp.limits.timestampPeriod;
244
-
vk->features.max_per_stage_descriptor_sampled_images = pdp.limits.maxPerStageDescriptorSampledImages;
245
-
vk->features.max_per_stage_descriptor_storage_images = pdp.limits.maxPerStageDescriptorStorageImages;
246
247
248
/*
···
975
return false;
976
}
977
978
-
static bool
979
build_device_extensions(struct vk_bundle *vk,
980
VkPhysicalDevice physical_device,
981
struct u_string_list *required_device_ext_list,
···
992
NULL, // layer_name
993
&prop_count, // out_prop_count
994
&props); // out_props
995
-
if (ret != VK_SUCCESS) {
996
-
VK_ERROR(vk, "vk_enumerate_physical_device_extension_properties: %s", vk_result_string(ret));
997
-
return false;
998
-
}
999
1000
uint32_t required_device_ext_count = u_string_list_get_size(required_device_ext_list);
1001
const char *const *required_device_exts = u_string_list_get_data(required_device_ext_list);
···
1004
for (uint32_t i = 0; i < required_device_ext_count; i++) {
1005
const char *ext = required_device_exts[i];
1006
if (!check_extension(vk, props, prop_count, ext)) {
1007
-
VK_DEBUG(vk, "VkPhysicalDevice does not support required extension %s", ext);
1008
free(props);
1009
-
return false;
1010
}
1011
VK_DEBUG(vk, "Using required device ext %s", ext);
1012
}
···
1042
1043
free(props);
1044
1045
-
1046
-
return true;
1047
}
1048
1049
/*!
···
1325
struct u_string_list *optional_device_ext_list,
1326
const struct vk_device_features *optional_device_features)
1327
{
1328
VkResult ret;
1329
1330
ret = select_physical_device(vk, forced_index);
1331
-
if (ret != VK_SUCCESS) {
1332
-
return ret;
1333
-
}
1334
1335
-
struct u_string_list *device_ext_list = NULL;
1336
-
if (!build_device_extensions(vk, vk->physical_device, required_device_ext_list, optional_device_ext_list,
1337
-
&device_ext_list)) {
1338
-
return VK_ERROR_EXTENSION_NOT_PRESENT;
1339
-
}
1340
1341
1342
/*
···
1359
if (!vk->has_EXT_global_priority && //
1360
!vk->has_KHR_global_priority && //
1361
global_priority != VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT) {
1362
-
return VK_ERROR_NOT_PERMITTED_EXT;
1363
}
1364
1365
vk_reset_queues(vk);
···
1367
struct vk_queue_family main_queue_family = {0};
1368
if (only_compute) {
1369
ret = find_queue_family(vk, VK_QUEUE_COMPUTE_BIT, &main_queue_family);
1370
} else {
1371
ret = find_graphics_queue_family(vk, &main_queue_family);
1372
-
}
1373
-
1374
-
if (ret != VK_SUCCESS) {
1375
-
return ret;
1376
}
1377
1378
assert(main_queue_family.queue_family.queueCount > 0);
···
1576
1577
ret = vk->vkCreateDevice(vk->physical_device, &device_create_info, NULL, &vk->device);
1578
1579
u_string_list_destroy(&device_ext_list);
1580
1581
-
if (ret != VK_SUCCESS) {
1582
-
VK_DEBUG(vk, "vkCreateDevice: %s (%d)", vk_result_string(ret), ret);
1583
-
if (ret == VK_ERROR_NOT_PERMITTED_EXT) {
1584
-
VK_DEBUG(vk, "Is CAP_SYS_NICE set? Try: sudo setcap cap_sys_nice+ep monado-service");
1585
-
}
1586
-
return ret;
1587
}
1588
1589
// Fill in the device features we are interested in.
1590
fill_in_device_features(vk, main_queue.family_index);
···
1594
1595
// Now setup all of the device specific functions.
1596
ret = vk_get_device_functions(vk);
1597
-
if (ret != VK_SUCCESS) {
1598
-
goto err_destroy;
1599
-
}
1600
1601
vk->main_queue = vk_insert_get_queue(vk, &main_queue);
1602
assert(vk->main_queue != NULL);
1603
#if defined(VK_KHR_video_encode_queue)
1604
vk->encode_queue = vk_insert_get_queue(vk, &encode_queue);
1605
#endif
···
1611
return ret;
1612
1613
err_destroy:
1614
-
vk->vkDestroyDevice(vk->device, NULL);
1615
-
vk->device = NULL;
1616
1617
return ret;
1618
}
···
241
242
vk->features.timestamp_compute_and_graphics = pdp.limits.timestampComputeAndGraphics;
243
vk->features.timestamp_period = pdp.limits.timestampPeriod;
244
+
245
+
vk->limits.max_sampler_allocation_count = pdp.limits.maxSamplerAllocationCount;
246
+
vk->limits.max_bound_descriptor_sets = pdp.limits.maxBoundDescriptorSets;
247
+
vk->limits.max_descriptor_set_samplers = pdp.limits.maxDescriptorSetSamplers;
248
+
vk->limits.max_descriptor_set_sampled_images = pdp.limits.maxDescriptorSetSampledImages;
249
+
vk->limits.max_per_stage_descriptor_samplers = pdp.limits.maxPerStageDescriptorSamplers;
250
+
vk->limits.max_per_stage_descriptor_sampled_images = pdp.limits.maxPerStageDescriptorSampledImages;
251
+
vk->limits.max_per_stage_descriptor_storage_images = pdp.limits.maxPerStageDescriptorStorageImages;
252
253
254
/*
···
981
return false;
982
}
983
984
+
static VkResult
985
build_device_extensions(struct vk_bundle *vk,
986
VkPhysicalDevice physical_device,
987
struct u_string_list *required_device_ext_list,
···
998
NULL, // layer_name
999
&prop_count, // out_prop_count
1000
&props); // out_props
1001
+
VK_CHK_AND_RET(ret, "vk_enumerate_physical_device_extension_properties");
1002
1003
uint32_t required_device_ext_count = u_string_list_get_size(required_device_ext_list);
1004
const char *const *required_device_exts = u_string_list_get_data(required_device_ext_list);
···
1007
for (uint32_t i = 0; i < required_device_ext_count; i++) {
1008
const char *ext = required_device_exts[i];
1009
if (!check_extension(vk, props, prop_count, ext)) {
1010
+
VK_ERROR(vk, "VkPhysicalDevice does not support required extension %s", ext);
1011
free(props);
1012
+
return VK_ERROR_EXTENSION_NOT_PRESENT;
1013
}
1014
VK_DEBUG(vk, "Using required device ext %s", ext);
1015
}
···
1045
1046
free(props);
1047
1048
+
return VK_SUCCESS;
1049
}
1050
1051
/*!
···
1327
struct u_string_list *optional_device_ext_list,
1328
const struct vk_device_features *optional_device_features)
1329
{
1330
+
struct u_string_list *device_ext_list = NULL;
1331
VkResult ret;
1332
1333
ret = select_physical_device(vk, forced_index);
1334
+
VK_CHK_WITH_GOTO(ret, "select_physical_device", err_destroy);
1335
1336
+
ret = build_device_extensions( //
1337
+
vk, //
1338
+
vk->physical_device, //
1339
+
required_device_ext_list, //
1340
+
optional_device_ext_list, //
1341
+
&device_ext_list); //
1342
+
VK_CHK_WITH_GOTO(ret, "build_device_extensions", err_destroy);
1343
1344
1345
/*
···
1362
if (!vk->has_EXT_global_priority && //
1363
!vk->has_KHR_global_priority && //
1364
global_priority != VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT) {
1365
+
ret = VK_ERROR_NOT_PERMITTED_EXT;
1366
+
goto err_destroy;
1367
}
1368
1369
vk_reset_queues(vk);
···
1371
struct vk_queue_family main_queue_family = {0};
1372
if (only_compute) {
1373
ret = find_queue_family(vk, VK_QUEUE_COMPUTE_BIT, &main_queue_family);
1374
+
VK_CHK_WITH_GOTO(ret, "find_queue_family", err_destroy);
1375
} else {
1376
ret = find_graphics_queue_family(vk, &main_queue_family);
1377
+
VK_CHK_WITH_GOTO(ret, "find_graphics_queue_family", err_destroy);
1378
}
1379
1380
assert(main_queue_family.queue_family.queueCount > 0);
···
1578
1579
ret = vk->vkCreateDevice(vk->physical_device, &device_create_info, NULL, &vk->device);
1580
1581
+
// Destroy the list now.
1582
u_string_list_destroy(&device_ext_list);
1583
1584
+
if (ret == VK_ERROR_NOT_PERMITTED_EXT) {
1585
+
// Don't spam the not permitted returns as we try all of the different priorities.
1586
+
VK_DEBUG(vk, "Is CAP_SYS_NICE set? Try: sudo setcap cap_sys_nice+ep monado-service");
1587
+
goto err_destroy;
1588
}
1589
+
VK_CHK_WITH_GOTO(ret, "vkCreateDevice", err_destroy);
1590
1591
// Fill in the device features we are interested in.
1592
fill_in_device_features(vk, main_queue.family_index);
···
1596
1597
// Now setup all of the device specific functions.
1598
ret = vk_get_device_functions(vk);
1599
+
VK_CHK_WITH_GOTO(ret, "vk_get_device_functions", err_destroy);
1600
1601
vk->main_queue = vk_insert_get_queue(vk, &main_queue);
1602
assert(vk->main_queue != NULL);
1603
+
1604
#if defined(VK_KHR_video_encode_queue)
1605
vk->encode_queue = vk_insert_get_queue(vk, &encode_queue);
1606
#endif
···
1612
return ret;
1613
1614
err_destroy:
1615
+
if (vk->device != VK_NULL_HANDLE) {
1616
+
vk->vkDestroyDevice(vk->device, NULL);
1617
+
vk->device = VK_NULL_HANDLE;
1618
+
}
1619
+
1620
+
// Safe to call even if null.
1621
+
u_string_list_destroy(&device_ext_list);
1622
1623
return ret;
1624
}
+27
-6
src/xrt/auxiliary/vk/vk_helpers.h
+27
-6
src/xrt/auxiliary/vk/vk_helpers.h
···
200
//! Were timeline semaphore requested, available, and enabled?
201
bool timeline_semaphore;
202
203
-
//! Per stage limit on sampled images (includes combined).
204
-
uint32_t max_per_stage_descriptor_sampled_images;
205
-
206
-
//! Per stage limit on storage images.
207
-
uint32_t max_per_stage_descriptor_storage_images;
208
-
209
//! Was synchronization2 requested, available, and enabled?
210
bool synchronization_2;
211
···
215
//! Was KHR_video_maintenance1 requested, available, and enabled?
216
bool video_maintenance_1;
217
} features;
218
219
//! Is the GPU a tegra device.
220
bool is_tegra;
···
1077
1078
/*!
1079
* Creates a VkDevice and initialises the VkQueue.
1080
*
1081
* @ingroup aux_vk
1082
*/
···
200
//! Were timeline semaphore requested, available, and enabled?
201
bool timeline_semaphore;
202
203
//! Was synchronization2 requested, available, and enabled?
204
bool synchronization_2;
205
···
209
//! Was KHR_video_maintenance1 requested, available, and enabled?
210
bool video_maintenance_1;
211
} features;
212
+
213
+
struct
214
+
{
215
+
//! Maximum number of sampler objects, as created by vkCreateSampler, which can simultaneously exist on
216
+
uint32_t max_sampler_allocation_count;
217
+
218
+
//! Maximum number of descriptor sets that can be simultaneously used by a pipeline.
219
+
uint32_t max_bound_descriptor_sets;
220
+
221
+
//! Maximum number of samplers that can be included in a pipeline layout.
222
+
uint32_t max_descriptor_set_samplers;
223
+
224
+
//! Maximum number of sampled images that can be included in a pipeline layout.
225
+
uint32_t max_descriptor_set_sampled_images;
226
+
227
+
//! Maximum number of samplers that can be accessible to a single shader stage in a pipeline layout.
228
+
uint32_t max_per_stage_descriptor_samplers;
229
+
230
+
//! Per stage limit on sampled images (includes combined).
231
+
uint32_t max_per_stage_descriptor_sampled_images;
232
+
233
+
//! Per stage limit on storage images.
234
+
uint32_t max_per_stage_descriptor_storage_images;
235
+
} limits;
236
237
//! Is the GPU a tegra device.
238
bool is_tegra;
···
1095
1096
/*!
1097
* Creates a VkDevice and initialises the VkQueue.
1098
+
*
1099
+
* The @p vk_bundle must have been zero initialized, have the instance functions
1100
+
* loaded and a valid instance.
1101
*
1102
* @ingroup aux_vk
1103
*/
+15
-6
src/xrt/auxiliary/vk/vk_image_allocator.c
+15
-6
src/xrt/auxiliary/vk/vk_image_allocator.c
···
184
.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID,
185
.externalFormat = a_buffer_format_props.externalFormat,
186
};
187
-
CHAIN(format_android);
188
189
if (image_format == VK_FORMAT_R8G8B8A8_SRGB) {
190
// Some versions of Android can't allocate native sRGB, use UNORM and correct gamma later.
···
192
193
// https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#VUID-VkImageViewCreateInfo-image-01019
194
image_create_flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
195
-
196
-
// https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkImageCreateInfo.html#VUID-VkImageCreateInfo-pNext-02396
197
-
format_android.externalFormat = 0;
198
-
assert(a_buffer_format_props.format != VK_FORMAT_UNDEFINED); // Make sure there is a Vulkan format.
199
-
assert(format_android.externalFormat == 0);
200
201
add_format_non_dup(&flh, VK_FORMAT_R8G8B8A8_UNORM);
202
add_format_non_dup(&flh, VK_FORMAT_R8G8B8A8_SRGB);
203
}
204
205
if (vk_csci_is_format_supported(vk, image_format, info->bits)) {
···
256
// VUID-VkImageCreateInfo-pNext-01974
257
if (format_android.externalFormat != 0) {
258
create_info.format = VK_FORMAT_UNDEFINED;
259
}
260
#endif
261
···
184
.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID,
185
.externalFormat = a_buffer_format_props.externalFormat,
186
};
187
188
if (image_format == VK_FORMAT_R8G8B8A8_SRGB) {
189
// Some versions of Android can't allocate native sRGB, use UNORM and correct gamma later.
···
191
192
// https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#VUID-VkImageViewCreateInfo-image-01019
193
image_create_flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
194
+
has_mutable_usage = true;
195
196
add_format_non_dup(&flh, VK_FORMAT_R8G8B8A8_UNORM);
197
add_format_non_dup(&flh, VK_FORMAT_R8G8B8A8_SRGB);
198
+
}
199
+
200
+
// https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkImageCreateInfo.html#VUID-VkImageCreateInfo-pNext-02396
201
+
if (has_mutable_usage) {
202
+
format_android.externalFormat = 0;
203
+
// Make sure there is a Vulkan format.
204
+
if (a_buffer_format_props.format == VK_FORMAT_UNDEFINED) {
205
+
VK_WARN(vk,
206
+
"vkGetAndroidHardwareBufferPropertiesANDROID: AHB has no Vulkan-mappable format. "
207
+
"External format chain required, but external formats cannot be mutable. Swapchain "
208
+
"creation may fail!");
209
+
assert(false);
210
+
}
211
}
212
213
if (vk_csci_is_format_supported(vk, image_format, info->bits)) {
···
264
// VUID-VkImageCreateInfo-pNext-01974
265
if (format_android.externalFormat != 0) {
266
create_info.format = VK_FORMAT_UNDEFINED;
267
+
CHAIN(format_android);
268
}
269
#endif
270
+21
-5
src/xrt/compositor/client/comp_d3d11_client.cpp
+21
-5
src/xrt/compositor/client/comp_d3d11_client.cpp
···
763
static void
764
client_d3d11_compositor_init_try_timeline_semaphores(struct client_d3d11_compositor *c)
765
{
766
c->timeline_semaphore_value = 1;
767
// See if we can make a "timeline semaphore", also known as ID3D11Fence
768
if (!c->xcn->base.create_semaphore || !c->xcn->base.layer_commit_with_semaphore) {
769
return;
770
}
771
-
struct xrt_compositor_semaphore *xcsem = nullptr;
772
-
wil::unique_handle timeline_semaphore_handle;
773
-
if (XRT_SUCCESS != xrt_comp_create_semaphore(&(c->xcn->base), timeline_semaphore_handle.put(), &xcsem)) {
774
D3D_WARN(c, "Native compositor tried but failed to created a timeline semaphore for us.");
775
return;
776
}
777
D3D_INFO(c, "Native compositor created a timeline semaphore for us.");
778
779
unique_compositor_semaphore_ref timeline_semaphore{xcsem};
780
781
-
// try to import and signal
782
-
wil::com_ptr<ID3D11Fence> fence = import_fence(*(c->fence_device), timeline_semaphore_handle.get());
783
HRESULT hr = c->fence_context->Signal(fence.get(), c->timeline_semaphore_value);
784
if (!SUCCEEDED(hr)) {
785
D3D_WARN(c,
···
763
static void
764
client_d3d11_compositor_init_try_timeline_semaphores(struct client_d3d11_compositor *c)
765
{
766
+
struct xrt_compositor_semaphore *xcsem{nullptr};
767
+
HANDLE timeline_semaphore_handle_raw{};
768
+
xrt_result_t xret;
769
+
770
+
// Set the value to something non-zero.
771
c->timeline_semaphore_value = 1;
772
+
773
// See if we can make a "timeline semaphore", also known as ID3D11Fence
774
if (!c->xcn->base.create_semaphore || !c->xcn->base.layer_commit_with_semaphore) {
775
return;
776
}
777
+
778
+
/*
779
+
* This call returns a HANDLE in the out_handle argument, it is owned by
780
+
* the returned xrt_compositor_semaphore object we should not track it.
781
+
*/
782
+
xret = xrt_comp_create_semaphore( //
783
+
&(c->xcn->base), // xc
784
+
&timeline_semaphore_handle_raw, // out_handle
785
+
&xcsem); // out_xcsem
786
+
if (xret != XRT_SUCCESS) {
787
D3D_WARN(c, "Native compositor tried but failed to created a timeline semaphore for us.");
788
return;
789
}
790
D3D_INFO(c, "Native compositor created a timeline semaphore for us.");
791
792
+
// Because importFence throws on failure we use this ref.
793
unique_compositor_semaphore_ref timeline_semaphore{xcsem};
794
795
+
// Try to import the fence.
796
+
wil::com_ptr<ID3D11Fence> fence = import_fence(*(c->fence_device), timeline_semaphore_handle_raw);
797
+
798
+
// And try to signal the fence to make sure it works.
799
HRESULT hr = c->fence_context->Signal(fence.get(), c->timeline_semaphore_value);
800
if (!SUCCEEDED(hr)) {
801
D3D_WARN(c,
+20
-7
src/xrt/compositor/client/comp_d3d12_client.cpp
+20
-7
src/xrt/compositor/client/comp_d3d12_client.cpp
···
1
// Copyright 2019-2024, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
801
}
802
struct xrt_layer_data d = *data;
803
804
// No flip required: D3D12 swapchain image convention matches Vulkan.
805
return xrt_comp_layer_projection(&c->xcn->base, xdev, xscn, &d);
806
}
···
1017
static void
1018
client_d3d12_compositor_init_try_timeline_semaphores(struct client_d3d12_compositor *c)
1019
{
1020
c->timeline_semaphore_value = 1;
1021
1022
// See if we can make a "timeline semaphore", also known as ID3D12Fence
···
1024
return;
1025
}
1026
1027
-
struct xrt_compositor_semaphore *xcsem = nullptr;
1028
-
wil::unique_handle timeline_semaphore_handle;
1029
-
if (XRT_SUCCESS != xrt_comp_create_semaphore(&(c->xcn->base), timeline_semaphore_handle.put(), &xcsem)) {
1030
D3D_WARN(c, "Native compositor tried but failed to created a timeline semaphore for us.");
1031
return;
1032
}
···
1038
// Try to import, importFence throws on failure.
1039
wil::com_ptr<ID3D12Fence1> fence = xrt::auxiliary::d3d::d3d12::importFence( //
1040
*(c->device), //
1041
-
timeline_semaphore_handle.get()); //
1042
-
1043
-
// The fence now owns the handle., importFence throws on failure.
1044
-
timeline_semaphore_handle.release();
1045
1046
// Check flags.
1047
D3D12_FENCE_FLAGS flags = fence->GetCreationFlags();
···
1
// Copyright 2019-2024, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
802
}
803
struct xrt_layer_data d = *data;
804
805
+
// Scale to compensate for power-of-two texture sizes.
806
+
for (uint32_t i = 0; i < data->view_count; ++i) {
807
+
client_d3d12_swapchain_scale_rect(xsc[i], &d.proj.v[i].sub.norm_rect);
808
+
}
809
// No flip required: D3D12 swapchain image convention matches Vulkan.
810
return xrt_comp_layer_projection(&c->xcn->base, xdev, xscn, &d);
811
}
···
1022
static void
1023
client_d3d12_compositor_init_try_timeline_semaphores(struct client_d3d12_compositor *c)
1024
{
1025
+
struct xrt_compositor_semaphore *xcsem{nullptr};
1026
+
HANDLE timeline_semaphore_handle_raw{};
1027
+
xrt_result_t xret;
1028
+
1029
+
// Set the value to something non-zero.
1030
c->timeline_semaphore_value = 1;
1031
1032
// See if we can make a "timeline semaphore", also known as ID3D12Fence
···
1034
return;
1035
}
1036
1037
+
/*
1038
+
* This call returns a HANDLE in the out_handle argument, it is owned by
1039
+
* the returned xrt_compositor_semaphore object we should not track it.
1040
+
*/
1041
+
xret = xrt_comp_create_semaphore( //
1042
+
&(c->xcn->base), // xc
1043
+
&timeline_semaphore_handle_raw, // out_handle
1044
+
&xcsem); // out_xcsem
1045
+
if (xret != XRT_SUCCESS) {
1046
D3D_WARN(c, "Native compositor tried but failed to created a timeline semaphore for us.");
1047
return;
1048
}
···
1054
// Try to import, importFence throws on failure.
1055
wil::com_ptr<ID3D12Fence1> fence = xrt::auxiliary::d3d::d3d12::importFence( //
1056
*(c->device), //
1057
+
timeline_semaphore_handle_raw); //
1058
1059
// Check flags.
1060
D3D12_FENCE_FLAGS flags = fence->GetCreationFlags();
+189
-19
src/xrt/compositor/client/comp_egl_client.c
+189
-19
src/xrt/compositor/client/comp_egl_client.c
···
200
#endif
201
}
202
203
static xrt_result_t
204
create_context(
205
EGLDisplay display, EGLConfig config, EGLContext app_context, EGLint api_type, EGLContext *out_our_context)
···
207
EGLint old_api_type = eglQueryAPI();
208
209
eglBindAPI(api_type);
210
211
-
size_t attrc = 0;
212
-
EGLint attrs[9] = {0};
213
-
214
-
attrs[attrc++] = EGL_CONTEXT_MAJOR_VERSION;
215
-
attrs[attrc++] = 3;
216
// Panfrost only supports 3.1
217
-
attrs[attrc++] = EGL_CONTEXT_MINOR_VERSION;
218
-
attrs[attrc++] = 1;
219
220
-
if (api_type == EGL_OPENGL_API) {
221
-
attrs[attrc++] = EGL_CONTEXT_OPENGL_PROFILE_MASK;
222
-
attrs[attrc++] = EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT;
223
}
224
225
-
EGLint strategy;
226
-
if (api_type == EGL_OPENGL_ES_API &&
227
-
eglQueryContext(display, app_context, EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, &strategy)) {
228
-
attrs[attrc++] = EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT;
229
-
attrs[attrc++] = strategy;
230
}
231
232
-
attrs[attrc++] = EGL_NONE;
233
-
assert(attrc <= ARRAY_SIZE(attrs));
234
235
-
EGLContext our_context = eglCreateContext(display, config, app_context, attrs);
236
237
// Restore old API type.
238
if (old_api_type == EGL_NONE) {
···
240
}
241
242
if (our_context == EGL_NO_CONTEXT) {
243
-
EGL_ERROR("eglCreateContext: %s", egl_error_str(eglGetError()));
244
return XRT_ERROR_OPENGL;
245
}
246
···
200
#endif
201
}
202
203
+
struct egl_attrs
204
+
{
205
+
EGLint api;
206
+
EGLint major;
207
+
EGLint minor;
208
+
bool compat_profile; // Only for desktop OpenGL
209
+
bool robust;
210
+
bool lose_context_on_reset;
211
+
EGLint image_prio;
212
+
};
213
+
214
+
static int
215
+
make_egl_attrs(EGLint *attrs, size_t len, const struct egl_attrs *params)
216
+
{
217
+
if (params->api != EGL_OPENGL_API && params->api != EGL_OPENGL_ES_API) {
218
+
U_LOG_E("make_egl_attrs: only OpenGL and OpenGL ES is supported");
219
+
return -1;
220
+
}
221
+
222
+
size_t attrc = 0;
223
+
224
+
#define ADD_ATTR(v) \
225
+
do { \
226
+
if (!len) { \
227
+
return -1; \
228
+
} \
229
+
len--; \
230
+
attrs[attrc++] = (v); \
231
+
} while (0)
232
+
233
+
#define ADD_PAIR(k, v) \
234
+
do { \
235
+
ADD_ATTR(k); \
236
+
ADD_ATTR(v); \
237
+
} while (0)
238
+
239
+
EGLint khr_flags = 0;
240
+
241
+
ADD_PAIR(EGL_CONTEXT_MAJOR_VERSION, params->major);
242
+
ADD_PAIR(EGL_CONTEXT_MINOR_VERSION, params->minor);
243
+
244
+
if (params->api == EGL_OPENGL_API && params->compat_profile) {
245
+
ADD_PAIR(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT);
246
+
}
247
+
248
+
if (params->robust) {
249
+
if (params->api == EGL_OPENGL_ES_API) {
250
+
ADD_PAIR(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_TRUE);
251
+
} else if (params->api == EGL_OPENGL_API) {
252
+
khr_flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
253
+
}
254
+
}
255
+
256
+
if (params->lose_context_on_reset) {
257
+
if (params->api == EGL_OPENGL_ES_API) {
258
+
ADD_PAIR(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, EGL_LOSE_CONTEXT_ON_RESET_EXT);
259
+
} else if (params->api == EGL_OPENGL_API) {
260
+
ADD_PAIR(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, EGL_LOSE_CONTEXT_ON_RESET_KHR);
261
+
}
262
+
}
263
+
264
+
if (params->api == EGL_OPENGL_API && khr_flags) {
265
+
ADD_PAIR(EGL_CONTEXT_FLAGS_KHR, khr_flags);
266
+
}
267
+
268
+
if (params->image_prio && params->image_prio != EGL_CONTEXT_PRIORITY_MEDIUM_IMG) {
269
+
ADD_PAIR(EGL_CONTEXT_PRIORITY_LEVEL_IMG, params->image_prio);
270
+
}
271
+
272
+
ADD_ATTR(EGL_NONE);
273
+
274
+
#undef ADD_ATTR
275
+
#undef ADD_PAIR
276
+
277
+
return attrc;
278
+
}
279
+
280
+
static void
281
+
print_egl_attrs(EGLint *attrs)
282
+
{
283
+
int i = 0;
284
+
EGL_DEBUG("egl attributes:");
285
+
do {
286
+
EGL_DEBUG("> attr: %d 0x%x", i, attrs[i]);
287
+
} while (attrs[i++] != EGL_NONE);
288
+
}
289
+
290
+
static EGLint
291
+
get_reset_strategy(EGLint api_type, EGLDisplay display, EGLContext app_context)
292
+
{
293
+
EGLint ext;
294
+
switch (api_type) {
295
+
case EGL_OPENGL_ES_API: ext = EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT; break;
296
+
case EGL_OPENGL_API:
297
+
/* This is non-standard, but supported in mesa */
298
+
ext = EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR;
299
+
break;
300
+
default: return 0;
301
+
}
302
+
303
+
EGLint strategy = 0;
304
+
if (!eglQueryContext(display, app_context, ext, &strategy)) {
305
+
return 0;
306
+
}
307
+
return strategy;
308
+
}
309
+
310
static xrt_result_t
311
create_context(
312
EGLDisplay display, EGLConfig config, EGLContext app_context, EGLint api_type, EGLContext *out_our_context)
···
314
EGLint old_api_type = eglQueryAPI();
315
316
eglBindAPI(api_type);
317
+
const char *api_string =
318
+
api_type == EGL_OPENGL_API ? "opengl" : (api_type == EGL_OPENGL_ES_API ? "opengl_es" : "");
319
320
// Panfrost only supports 3.1
321
+
const EGLint major = 3;
322
+
const EGLint minor = 1;
323
324
+
EGLint image_prio;
325
+
if (!eglQueryContext(display, app_context, EGL_CONTEXT_PRIORITY_LEVEL_IMG, &image_prio)) {
326
+
image_prio = 0;
327
}
328
329
+
const size_t attrs_len = 21;
330
+
EGLint attrs[4][attrs_len];
331
+
int attrc = 0;
332
+
333
+
struct egl_attrs build_attrs = {
334
+
.api = api_type,
335
+
.major = major,
336
+
.minor = minor,
337
+
.compat_profile = true,
338
+
.image_prio = image_prio,
339
+
};
340
+
341
+
/* If the source context was created with robust and/or lose notify enabled,
342
+
* then we need to enable it too or we get EGL_BAD_MATCH.
343
+
*
344
+
* Problems with those options:
345
+
* 1. Different way to activate them for OpenGL and OpenGL ES.
346
+
* 2. No standard way to know if the options were used to create the original context.
347
+
* (with an exception for OpenGL ES)
348
+
*
349
+
* So, the most reliable way to create our shared context is to try all those combinations...
350
+
*/
351
+
EGLint reset_strategy = get_reset_strategy(api_type, display, app_context);
352
+
EGL_DEBUG("Current reset strategy (%s): 0x%x", api_string, reset_strategy);
353
+
if (reset_strategy) {
354
+
build_attrs.lose_context_on_reset = (reset_strategy == EGL_LOSE_CONTEXT_ON_RESET);
355
+
356
+
if (make_egl_attrs(attrs[attrc++], attrs_len, &build_attrs) == -1) {
357
+
return XRT_ERROR_OPENGL;
358
+
}
359
+
360
+
build_attrs.robust = true;
361
+
if (make_egl_attrs(attrs[attrc++], attrs_len, &build_attrs) == -1) {
362
+
return XRT_ERROR_OPENGL;
363
+
}
364
+
} else {
365
+
/* Try context with all optional features disabled first */
366
+
if (make_egl_attrs(attrs[attrc++], attrs_len, &build_attrs) == -1) {
367
+
return XRT_ERROR_OPENGL;
368
+
}
369
+
370
+
/* Then, try all combination of robustness and lose notification */
371
+
build_attrs.robust = false;
372
+
build_attrs.lose_context_on_reset = true;
373
+
if (make_egl_attrs(attrs[attrc++], attrs_len, &build_attrs) == -1) {
374
+
return XRT_ERROR_OPENGL;
375
+
}
376
+
377
+
build_attrs.robust = true;
378
+
build_attrs.lose_context_on_reset = false;
379
+
if (make_egl_attrs(attrs[attrc++], attrs_len, &build_attrs) == -1) {
380
+
return XRT_ERROR_OPENGL;
381
+
}
382
+
383
+
build_attrs.robust = true;
384
+
build_attrs.lose_context_on_reset = true;
385
+
if (make_egl_attrs(attrs[attrc++], attrs_len, &build_attrs) == -1) {
386
+
return XRT_ERROR_OPENGL;
387
+
}
388
}
389
390
+
assert((unsigned)attrc <= ARRAY_SIZE(attrs));
391
392
+
EGLContext our_context = EGL_NO_CONTEXT;
393
+
const char *last_error = "";
394
+
for (int i = 0; i != attrc; i++) {
395
+
our_context = eglCreateContext(display, config, app_context, attrs[i]);
396
+
if (our_context != EGL_NO_CONTEXT) {
397
+
EGL_DEBUG("eglCreateContext (%s): try %d, context created", api_string, i);
398
+
print_egl_attrs(attrs[i]);
399
+
break;
400
+
}
401
+
402
+
last_error = egl_error_str(eglGetError());
403
+
EGL_DEBUG("eglCreateContext (%s): try %d, %s", api_string, i, last_error);
404
+
print_egl_attrs(attrs[i]);
405
+
}
406
407
// Restore old API type.
408
if (old_api_type == EGL_NONE) {
···
410
}
411
412
if (our_context == EGL_NO_CONTEXT) {
413
+
EGL_ERROR("eglCreateContext (%s): %s", api_string, last_error);
414
return XRT_ERROR_OPENGL;
415
}
416
+27
-11
src/xrt/compositor/main/comp_compositor.c
+27
-11
src/xrt/compositor/main/comp_compositor.c
···
1031
1032
COMP_DEBUG(c, "Doing init %p", (void *)c);
1033
1034
-
if (xdev->hmd->view_count == 0) {
1035
-
U_LOG_E("Bug detected: HMD \"%s\" does not set xdev->hmd.view_count. Value must be > 0!", xdev->str);
1036
assert(xdev->hmd->view_count > 0);
1037
}
1038
1039
// Do this as early as possible.
···
1121
struct xrt_system_compositor_info sys_info_storage = {0};
1122
struct xrt_system_compositor_info *sys_info = &sys_info_storage;
1123
1124
-
// Required by OpenXR spec.
1125
-
sys_info->max_layers = XRT_MAX_LAYERS;
1126
sys_info->compositor_vk_deviceUUID = c->settings.selected_gpu_deviceUUID;
1127
sys_info->client_vk_deviceUUID = c->settings.client_gpu_deviceUUID;
1128
sys_info->client_d3d_deviceLUID = c->settings.client_gpu_deviceLUID;
···
1131
sys_info->supports_fov_mutable = true;
1132
1133
// clang-format off
1134
-
uint32_t view_count = xdev->hmd->view_count;
1135
for (uint32_t i = 0; i < view_count; ++i) {
1136
uint32_t w = (uint32_t)(xdev->hmd->views[i].display.w_pixels * scale);
1137
uint32_t h = (uint32_t)(xdev->hmd->views[i].display.h_pixels * scale);
1138
uint32_t w_2 = xdev->hmd->views[i].display.w_pixels * 2;
1139
uint32_t h_2 = xdev->hmd->views[i].display.h_pixels * 2;
1140
1141
-
sys_info->views[i].recommended.width_pixels = w;
1142
-
sys_info->views[i].recommended.height_pixels = h;
1143
-
sys_info->views[i].recommended.sample_count = 1;
1144
-
sys_info->views[i].max.width_pixels = w_2;
1145
-
sys_info->views[i].max.height_pixels = h_2;
1146
-
sys_info->views[i].max.sample_count = 1;
1147
}
1148
// clang-format on
1149
1150
// If we can add e.g. video pass-through capabilities, we may need to change (augment) this list.
1151
// Just copying it directly right now.
···
1031
1032
COMP_DEBUG(c, "Doing init %p", (void *)c);
1033
1034
+
uint32_t view_count = xdev->hmd->view_count;
1035
+
enum xrt_view_type view_type = 0; // Invalid
1036
+
1037
+
switch (view_count) {
1038
+
case 0:
1039
+
U_LOG_E("Bug detected: HMD \"%s\" xdev->hmd.view_count must be > 0!", xdev->str);
1040
assert(xdev->hmd->view_count > 0);
1041
+
break;
1042
+
case 1: view_type = XRT_VIEW_TYPE_MONO; break;
1043
+
case 2: view_type = XRT_VIEW_TYPE_STEREO; break;
1044
+
default:
1045
+
U_LOG_E("Bug detected: HMD \"%s\" xdev->hmd.view_count must be 1 or 2, not %u!", xdev->str, view_count);
1046
+
assert(view_count == 1 && view_count == 2);
1047
+
break;
1048
}
1049
1050
// Do this as early as possible.
···
1132
struct xrt_system_compositor_info sys_info_storage = {0};
1133
struct xrt_system_compositor_info *sys_info = &sys_info_storage;
1134
1135
+
// Required by OpenXR spec (minimum 16).
1136
+
sys_info->max_layers = render_max_layers_capable( //
1137
+
get_vk(c), //
1138
+
c->settings.use_compute, //
1139
+
XRT_MAX_LAYERS); //
1140
sys_info->compositor_vk_deviceUUID = c->settings.selected_gpu_deviceUUID;
1141
sys_info->client_vk_deviceUUID = c->settings.client_gpu_deviceUUID;
1142
sys_info->client_d3d_deviceLUID = c->settings.client_gpu_deviceLUID;
···
1145
sys_info->supports_fov_mutable = true;
1146
1147
// clang-format off
1148
for (uint32_t i = 0; i < view_count; ++i) {
1149
uint32_t w = (uint32_t)(xdev->hmd->views[i].display.w_pixels * scale);
1150
uint32_t h = (uint32_t)(xdev->hmd->views[i].display.h_pixels * scale);
1151
uint32_t w_2 = xdev->hmd->views[i].display.w_pixels * 2;
1152
uint32_t h_2 = xdev->hmd->views[i].display.h_pixels * 2;
1153
1154
+
sys_info->view_configs[0].views[i].recommended.width_pixels = w;
1155
+
sys_info->view_configs[0].views[i].recommended.height_pixels = h;
1156
+
sys_info->view_configs[0].views[i].recommended.sample_count = 1;
1157
+
sys_info->view_configs[0].views[i].max.width_pixels = w_2;
1158
+
sys_info->view_configs[0].views[i].max.height_pixels = h_2;
1159
+
sys_info->view_configs[0].views[i].max.sample_count = 1;
1160
}
1161
// clang-format on
1162
+
sys_info->view_configs[0].view_type = view_type;
1163
+
sys_info->view_configs[0].view_count = view_count;
1164
+
sys_info->view_config_count = 1; // Only one view config for now.
1165
1166
// If we can add e.g. video pass-through capabilities, we may need to change (augment) this list.
1167
// Just copying it directly right now.
+7
-2
src/xrt/compositor/main/comp_renderer.c
+7
-2
src/xrt/compositor/main/comp_renderer.c
···
259
struct xrt_fov xdev_fovs[XRT_MAX_VIEWS] = XRT_STRUCT_INIT;
260
struct xrt_pose xdev_poses[2][XRT_MAX_VIEWS] = XRT_STRUCT_INIT;
261
262
-
uint64_t scanout_time_ns = 0;
263
if (r->c->xdev->hmd->screens[0].scanout_direction == XRT_SCANOUT_DIRECTION_TOP_TO_BOTTOM) {
264
scanout_time_ns = r->c->xdev->hmd->screens[0].scanout_time_ns;
265
} else if (r->c->xdev->hmd->screens[0].scanout_direction != XRT_SCANOUT_DIRECTION_NONE) {
···
274
r->c->xdev, //
275
&default_eye_relation, //
276
begin_timestamp_ns, // at_timestamp_ns
277
view_count, //
278
&head_relation[0], // out_head_relation
279
xdev_fovs, // out_fovs
280
-
xdev_poses[0]);
281
if (xret != XRT_SUCCESS) {
282
struct u_pp_sink_stack_only sink;
283
u_pp_delegate_t dg = u_pp_sink_stack_only_init(&sink);
···
292
r->c->xdev, //
293
&default_eye_relation, //
294
end_timestamp_ns, // at_timestamp_ns
295
view_count, //
296
&head_relation[1], // out_head_relation
297
xdev_fovs, // out_fovs
···
259
struct xrt_fov xdev_fovs[XRT_MAX_VIEWS] = XRT_STRUCT_INIT;
260
struct xrt_pose xdev_poses[2][XRT_MAX_VIEWS] = XRT_STRUCT_INIT;
261
262
+
// Determine view type based on view count
263
+
enum xrt_view_type view_type = (view_count == 1) ? XRT_VIEW_TYPE_MONO : XRT_VIEW_TYPE_STEREO;
264
+
265
+
int64_t scanout_time_ns = 0;
266
if (r->c->xdev->hmd->screens[0].scanout_direction == XRT_SCANOUT_DIRECTION_TOP_TO_BOTTOM) {
267
scanout_time_ns = r->c->xdev->hmd->screens[0].scanout_time_ns;
268
} else if (r->c->xdev->hmd->screens[0].scanout_direction != XRT_SCANOUT_DIRECTION_NONE) {
···
277
r->c->xdev, //
278
&default_eye_relation, //
279
begin_timestamp_ns, // at_timestamp_ns
280
+
view_type, //
281
view_count, //
282
&head_relation[0], // out_head_relation
283
xdev_fovs, // out_fovs
284
+
xdev_poses[0]); //
285
if (xret != XRT_SUCCESS) {
286
struct u_pp_sink_stack_only sink;
287
u_pp_delegate_t dg = u_pp_sink_stack_only_init(&sink);
···
296
r->c->xdev, //
297
&default_eye_relation, //
298
end_timestamp_ns, // at_timestamp_ns
299
+
view_type, //
300
view_count, //
301
&head_relation[1], // out_head_relation
302
xdev_fovs, // out_fovs
+4
src/xrt/compositor/main/comp_settings.c
+4
src/xrt/compositor/main/comp_settings.c
+2
-2
src/xrt/compositor/main/comp_window_direct.c
+2
-2
src/xrt/compositor/main/comp_window_direct.c
···
64
COMP_PRINT_MODE(ct->c, "Available Vk modes for direct mode");
65
for (int i = 0; i < mode_count; i++) {
66
VkDisplayModePropertiesKHR *props = &mode_properties[i];
67
-
uint16_t width = props->parameters.visibleRegion.width;
68
-
uint16_t height = props->parameters.visibleRegion.height;
69
float refresh = (float)props->parameters.refreshRate / 1000.f;
70
71
COMP_PRINT_MODE(ct->c, "| %2d | %dx%d@%.2f", i, width, height, refresh);
···
64
COMP_PRINT_MODE(ct->c, "Available Vk modes for direct mode");
65
for (int i = 0; i < mode_count; i++) {
66
VkDisplayModePropertiesKHR *props = &mode_properties[i];
67
+
uint32_t width = props->parameters.visibleRegion.width;
68
+
uint32_t height = props->parameters.visibleRegion.height;
69
float refresh = (float)props->parameters.refreshRate / 1000.f;
70
71
COMP_PRINT_MODE(ct->c, "| %2d | %dx%d@%.2f", i, width, height, refresh);
+16
-3
src/xrt/compositor/multi/comp_multi_system.c
+16
-3
src/xrt/compositor/multi/comp_multi_system.c
···
1
// Copyright 2019-2024, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
422
.fb_face_tracking2_enabled = false,
423
.meta_body_tracking_full_body_enabled = false,
424
.meta_body_tracking_calibration_enabled = false,
425
};
426
427
switch (msc->sessions.state) {
···
556
U_LOG_I("Stopped native session, shutting down.");
557
xrt_comp_end_session(xc);
558
break;
559
-
case MULTI_SYSTEM_STATE_STOPPED: break;
560
-
default: assert(false);
561
}
562
563
os_thread_helper_unlock(&msc->oth);
···
581
*/
582
583
static xrt_result_t
584
-
system_compositor_set_state(struct xrt_system_compositor *xsc, struct xrt_compositor *xc, bool visible, bool focused)
585
{
586
struct multi_system_compositor *msc = multi_system_compositor(xsc);
587
struct multi_compositor *mc = multi_compositor(xc);
···
596
xse.type = XRT_SESSION_EVENT_STATE_CHANGE;
597
xse.state.visible = visible;
598
xse.state.focused = focused;
599
600
return multi_compositor_push_event(mc, &xse);
601
}
···
1
// Copyright 2019-2024, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
423
.fb_face_tracking2_enabled = false,
424
.meta_body_tracking_full_body_enabled = false,
425
.meta_body_tracking_calibration_enabled = false,
426
+
.android_face_tracking_enabled = false,
427
};
428
429
switch (msc->sessions.state) {
···
558
U_LOG_I("Stopped native session, shutting down.");
559
xrt_comp_end_session(xc);
560
break;
561
+
case MULTI_SYSTEM_STATE_STOPPED: U_LOG_I("Already stopped, nothing to clean up."); break;
562
+
case MULTI_SYSTEM_STATE_INIT_WARM_START:
563
+
U_LOG_I("Cleaning up from warm start state.");
564
+
xrt_comp_end_session(xc);
565
+
break;
566
+
case MULTI_SYSTEM_STATE_INVALID:
567
+
U_LOG_W("Cleaning up from invalid state.");
568
+
// Best effort cleanup
569
+
xrt_comp_end_session(xc);
570
+
break;
571
+
default: U_LOG_E("Unknown session state during cleanup: %d", msc->sessions.state); assert(false);
572
}
573
574
os_thread_helper_unlock(&msc->oth);
···
592
*/
593
594
static xrt_result_t
595
+
system_compositor_set_state(
596
+
struct xrt_system_compositor *xsc, struct xrt_compositor *xc, bool visible, bool focused, int64_t timestamp_ns)
597
{
598
struct multi_system_compositor *msc = multi_system_compositor(xsc);
599
struct multi_compositor *mc = multi_compositor(xc);
···
608
xse.type = XRT_SESSION_EVENT_STATE_CHANGE;
609
xse.state.visible = visible;
610
xse.state.focused = focused;
611
+
xse.state.timestamp_ns = timestamp_ns;
612
613
return multi_compositor_push_event(mc, &xse);
614
}
+38
-10
src/xrt/compositor/null/null_compositor.c
+38
-10
src/xrt/compositor/null/null_compositor.c
···
268
{
269
struct xrt_system_compositor_info *sys_info = &c->sys_info;
270
271
-
// Required by OpenXR spec.
272
sys_info->max_layers = XRT_MAX_LAYERS;
273
274
// UUIDs and LUID already set in vk init.
275
(void)sys_info->compositor_vk_deviceUUID;
276
(void)sys_info->client_vk_deviceUUID;
277
(void)sys_info->client_d3d_deviceLUID;
278
(void)sys_info->client_d3d_deviceLUID_valid;
279
-
uint32_t view_count = xdev->hmd->view_count;
280
// clang-format off
281
for (uint32_t i = 0; i < view_count; ++i) {
282
-
sys_info->views[i].recommended.width_pixels = RECOMMENDED_VIEW_WIDTH;
283
-
sys_info->views[i].recommended.height_pixels = RECOMMENDED_VIEW_HEIGHT;
284
-
sys_info->views[i].recommended.sample_count = 1;
285
-
sys_info->views[i].max.width_pixels = MAX_VIEW_WIDTH;
286
-
sys_info->views[i].max.height_pixels = MAX_VIEW_HEIGHT;
287
-
sys_info->views[i].max.sample_count = 1;
288
}
289
// clang-format on
290
291
// Copy the list directly.
292
assert(xdev->hmd->blend_mode_count <= XRT_MAX_DEVICE_BLEND_MODES);
···
436
437
struct xrt_fov fovs[2] = {0};
438
struct xrt_pose poses[2] = {0};
439
-
xrt_result_t xret =
440
-
xrt_device_get_view_poses(c->xdev, &default_eye_relation, display_time_ns, 2, &head_relation, fovs, poses);
441
if (xret != XRT_SUCCESS) {
442
return xret;
443
}
···
268
{
269
struct xrt_system_compositor_info *sys_info = &c->sys_info;
270
271
+
/*
272
+
* Required by OpenXR spec (minimum 16).
273
+
*
274
+
* NOTE: When using Vulkan compositor components (c/render, c/util),
275
+
* call render_max_layers_capable() to clamp this value based on
276
+
* actual device limits.
277
+
*/
278
sys_info->max_layers = XRT_MAX_LAYERS;
279
280
+
uint32_t view_count = xdev->hmd->view_count;
281
+
enum xrt_view_type view_type = 0; // Invalid
282
+
283
+
switch (view_count) {
284
+
case 0: U_LOG_E("Bug detected: HMD \"%s\" xdev->hmd.view_count must be > 0!", xdev->str); return false;
285
+
case 1: view_type = XRT_VIEW_TYPE_MONO; break;
286
+
case 2: view_type = XRT_VIEW_TYPE_STEREO; break;
287
+
default:
288
+
U_LOG_E("Bug detected: HMD \"%s\" xdev->hmd.view_count must be 1 or 2, not %u!", xdev->str, view_count);
289
+
return false;
290
+
}
291
+
292
// UUIDs and LUID already set in vk init.
293
(void)sys_info->compositor_vk_deviceUUID;
294
(void)sys_info->client_vk_deviceUUID;
295
(void)sys_info->client_d3d_deviceLUID;
296
(void)sys_info->client_d3d_deviceLUID_valid;
297
// clang-format off
298
for (uint32_t i = 0; i < view_count; ++i) {
299
+
sys_info->view_configs[0].views[i].recommended.width_pixels = RECOMMENDED_VIEW_WIDTH;
300
+
sys_info->view_configs[0].views[i].recommended.height_pixels = RECOMMENDED_VIEW_HEIGHT;
301
+
sys_info->view_configs[0].views[i].recommended.sample_count = 1;
302
+
sys_info->view_configs[0].views[i].max.width_pixels = MAX_VIEW_WIDTH;
303
+
sys_info->view_configs[0].views[i].max.height_pixels = MAX_VIEW_HEIGHT;
304
+
sys_info->view_configs[0].views[i].max.sample_count = 1;
305
}
306
// clang-format on
307
+
sys_info->view_configs[0].view_type = view_type;
308
+
sys_info->view_configs[0].view_count = view_count;
309
+
sys_info->view_config_count = 1; // Only one view config type supported.
310
311
// Copy the list directly.
312
assert(xdev->hmd->blend_mode_count <= XRT_MAX_DEVICE_BLEND_MODES);
···
456
457
struct xrt_fov fovs[2] = {0};
458
struct xrt_pose poses[2] = {0};
459
+
460
+
xrt_result_t xret = xrt_device_get_view_poses( //
461
+
c->xdev, //
462
+
&default_eye_relation, //
463
+
display_time_ns, //
464
+
XRT_VIEW_TYPE_STEREO, //
465
+
2, //
466
+
&head_relation, //
467
+
fovs, //
468
+
poses); //
469
if (xret != XRT_SUCCESS) {
470
return xret;
471
}
+48
-12
src/xrt/compositor/render/render_interface.h
+48
-12
src/xrt/compositor/render/render_interface.h
···
1
// Copyright 2019-2023, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
58
#define RENDER_MAX_LAYERS (XRT_MAX_LAYERS)
59
60
/*!
61
* Max number of images that can be given at a single time to the layer
62
* squasher in a single dispatch.
63
*/
64
-
#define RENDER_MAX_IMAGES_SIZE (RENDER_MAX_LAYERS * XRT_MAX_VIEWS)
65
-
#define RENDER_MAX_IMAGES_COUNT(RENDER_RESOURCES) (RENDER_MAX_LAYERS * RENDER_RESOURCES->view_count)
66
67
/*!
68
* Maximum number of times that the layer squasher shader can run per
···
87
//! The binding that the shared layer fragment shader has its source on.
88
#define RENDER_BINDING_LAYER_SHARED_SRC 1
89
90
91
/*
92
*
93
* Util functions.
94
*
95
*/
96
97
/*!
98
* Create a simplified projection matrix for timewarp.
···
1207
struct
1208
{
1209
uint32_t value;
1210
-
uint32_t padding[3];
1211
} layer_count;
1212
1213
struct xrt_normalized_rect pre_transform;
1214
struct xrt_normalized_rect post_transforms[RENDER_MAX_LAYERS];
1215
1216
-
//! std140 uvec2, corresponds to enum xrt_layer_type and unpremultiplied alpha.
1217
struct
1218
{
1219
-
uint32_t val;
1220
-
uint32_t unpremultiplied;
1221
-
uint32_t padding[XRT_MAX_VIEWS];
1222
-
} layer_type[RENDER_MAX_LAYERS];
1223
1224
-
//! Which image/sampler(s) correspond to each layer.
1225
struct
1226
{
1227
-
uint32_t images[XRT_MAX_VIEWS];
1228
//! @todo Implement separated samplers and images (and change to samplers[2])
1229
-
uint32_t padding[XRT_MAX_VIEWS];
1230
-
} images_samplers[RENDER_MAX_LAYERS];
1231
1232
//! Shared between cylinder and equirect2.
1233
struct xrt_matrix_4x4 mv_inverse[RENDER_MAX_LAYERS];
···
1
// Copyright 2019-2023, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
59
#define RENDER_MAX_LAYERS (XRT_MAX_LAYERS)
60
61
/*!
62
+
* The maximum number samplers per view that can be used by the compute shader
63
+
* for layer composition (layer.comp)
64
+
*/
65
+
#define RENDER_CS_MAX_SAMPLERS_PER_VIEW 2
66
+
67
+
/*!
68
* Max number of images that can be given at a single time to the layer
69
* squasher in a single dispatch.
70
*/
71
+
#define RENDER_MAX_IMAGES_SIZE (RENDER_MAX_LAYERS * RENDER_CS_MAX_SAMPLERS_PER_VIEW)
72
73
/*!
74
* Maximum number of times that the layer squasher shader can run per
···
93
//! The binding that the shared layer fragment shader has its source on.
94
#define RENDER_BINDING_LAYER_SHARED_SRC 1
95
96
+
/*!
97
+
* The maximum number samplers per view that can be used by the compute shader
98
+
* for layer composition (layer.comp)
99
+
*/
100
+
#define RENDER_CS_MAX_SAMPLERS_PER_VIEW 2
101
102
/*
103
*
104
* Util functions.
105
*
106
*/
107
+
108
+
/*!
109
+
* Determines the maximum number of compositor layers supported based on Vulkan
110
+
* device limits and the composition path being used.
111
+
*
112
+
* @param vk Vulkan bundle containing device properties
113
+
* @param use_compute True if using compute pipeline path, false for graphics
114
+
* @param desired_max_layers Maximum layers requested by the compositor
115
+
* @return Actual maximum layers supported, clamped by device limits (minimum 16)
116
+
*
117
+
*/
118
+
uint32_t
119
+
render_max_layers_capable(const struct vk_bundle *vk, bool use_compute, uint32_t desired_max_layers);
120
121
/*!
122
* Create a simplified projection matrix for timewarp.
···
1231
struct
1232
{
1233
uint32_t value;
1234
+
uint32_t padding[3]; // Padding up to a vec4.
1235
} layer_count;
1236
1237
struct xrt_normalized_rect pre_transform;
1238
struct xrt_normalized_rect post_transforms[RENDER_MAX_LAYERS];
1239
1240
+
/*!
1241
+
* Corresponds to enum xrt_layer_type and unpremultiplied alpha.
1242
+
*
1243
+
* std140 uvec2, because it is an array it gets padded to vec4.
1244
+
*/
1245
struct
1246
{
1247
+
uint32_t layer_type;
1248
+
uint32_t unpremultiplied_alpha;
1249
+
uint32_t _padding0;
1250
+
uint32_t _padding1;
1251
+
} layer_data[RENDER_MAX_LAYERS];
1252
1253
+
/*!
1254
+
* Which image/sampler(s) correspond to each layer.
1255
+
*
1256
+
* std140 uvec2, because it is an array it gets padded to vec4.
1257
+
*/
1258
struct
1259
{
1260
+
uint32_t color_image_index;
1261
+
uint32_t depth_image_index;
1262
+
1263
//! @todo Implement separated samplers and images (and change to samplers[2])
1264
+
uint32_t _padding0;
1265
+
uint32_t _padding1;
1266
+
} image_info[RENDER_MAX_LAYERS];
1267
1268
//! Shared between cylinder and equirect2.
1269
struct xrt_matrix_4x4 mv_inverse[RENDER_MAX_LAYERS];
+1
-1
src/xrt/compositor/render/render_resources.c
+1
-1
src/xrt/compositor/render/render_resources.c
+49
src/xrt/compositor/render/render_util.c
+49
src/xrt/compositor/render/render_util.c
···
87
*
88
*/
89
90
+
uint32_t
91
+
render_max_layers_capable(const struct vk_bundle *vk, bool use_compute, uint32_t desired_max_layers)
92
+
{
93
+
/*!
94
+
* Graphics pipeline:
95
+
*
96
+
* This path has no relevant Vulkan device limits that would
97
+
* constrain the maximum number of layers (each layer uses a single descriptor
98
+
* set bound individually per draw).
99
+
*/
100
+
if (!use_compute) {
101
+
// The min required by OpenXR spec is 16.
102
+
return MAX(desired_max_layers, 16);
103
+
}
104
+
105
+
/*!
106
+
* Compute pipeline:
107
+
*
108
+
* Clamp max layers based on compute pipeline descriptor limits.
109
+
*
110
+
* The compute path uses an array of combined image samplers, with
111
+
* @ref samplers_per_layer samplers needed per layer. We check both the
112
+
* per-stage sampler and sampled image limits, then calculate the
113
+
* maximum number of complete layers that fit within those limits.
114
+
*/
115
+
uint32_t desired_image_sampler_count = desired_max_layers * RENDER_CS_MAX_SAMPLERS_PER_VIEW;
116
+
117
+
const uint32_t max_sizes[] = {
118
+
vk->limits.max_per_stage_descriptor_samplers,
119
+
vk->limits.max_per_stage_descriptor_sampled_images,
120
+
};
121
+
for (uint32_t i = 0; i < ARRAY_SIZE(max_sizes); ++i) {
122
+
desired_image_sampler_count = MIN(desired_image_sampler_count, max_sizes[i]);
123
+
}
124
+
125
+
const uint32_t calculated_max_layers = desired_image_sampler_count / RENDER_CS_MAX_SAMPLERS_PER_VIEW;
126
+
127
+
if (calculated_max_layers < 16) {
128
+
VK_WARN(vk,
129
+
"Device supports only %u compositor layers due to Vulkan limits. "
130
+
"which is below Vulkan minimum of 16. "
131
+
"This may indicate a driver bug. Attempting 16 anyway.",
132
+
calculated_max_layers);
133
+
}
134
+
135
+
// The min required by OpenXR spec is 16.
136
+
return MAX(calculated_max_layers, 16);
137
+
}
138
+
139
void
140
render_calc_time_warp_matrix(const struct xrt_pose *src_pose,
141
const struct xrt_fov *src_fov,
+38
-24
src/xrt/compositor/shaders/layer.comp
+38
-24
src/xrt/compositor/shaders/layer.comp
···
1
// Copyright 2021-2023, Collabora Ltd.
2
// Author: Jakob Bornecrantz <jakob@collabora.com>
3
// Author: Christoph Haag <christoph.haag@collabora.com>
4
// SPDX-License-Identifier: BSL-1.0
···
7
#extension GL_GOOGLE_include_directive : require
8
9
#include "srgb.inc.glsl"
10
11
-
//! @todo should this be a spcialization const?
12
-
#define XRT_LAYER_PROJECTION 0
13
-
#define XRT_LAYER_PROJECTION_DEPTH 1
14
-
#define XRT_LAYER_QUAD 2
15
-
#define XRT_LAYER_CUBE 3
16
-
#define XRT_LAYER_CYLINDER 4
17
-
#define XRT_LAYER_EQUIRECT1 5
18
-
#define XRT_LAYER_EQUIRECT2 6
19
20
const float PI = acos(-1);
21
···
40
vec4 pre_transform;
41
vec4 post_transform[RENDER_MAX_LAYERS];
42
43
-
// corresponds to enum xrt_layer_type
44
-
uvec2 layer_type_and_unpremultiplied[RENDER_MAX_LAYERS];
45
46
// which image/sampler(s) correspond to each layer
47
-
ivec2 images_samplers[RENDER_MAX_LAYERS];
48
49
// shared between cylinder and equirect2
50
mat4 mv_inverse[RENDER_MAX_LAYERS];
···
226
227
vec2 uv_sub = fma(sample_point, ubo.post_transform[layer].zw, ubo.post_transform[layer].xy);
228
229
-
uint index = ubo.images_samplers[layer].x;
230
#ifdef DEBUG
231
out_color += texture(source[index], uv_sub) / 2.f;
232
#else
···
325
326
vec2 uv_sub = fma(sample_point, ubo.post_transform[layer].zw, ubo.post_transform[layer].xy);
327
328
-
uint index = ubo.images_samplers[layer].x;
329
#ifdef DEBUG
330
out_color += texture(source[index], uv_sub) / 2.0;
331
#else
···
341
342
vec4 do_projection(vec2 view_uv, uint layer)
343
{
344
-
uint source_image_index = ubo.images_samplers[layer].x;
345
346
// Do any transformation needed.
347
vec2 uv = transform_uv(view_uv, layer);
···
373
374
vec4 do_quad(vec2 view_uv, uint layer)
375
{
376
-
uint source_image_index = ubo.images_samplers[layer].x;
377
378
// center point of the plane in view space.
379
vec3 quad_position = ubo.quad_position[layer].xyz;
···
459
for (uint layer = 0; layer < layer_count; layer++) {
460
vec4 rgba = vec4(0, 0, 0, 0);
461
462
-
switch (ubo.layer_type_and_unpremultiplied[layer].x) {
463
-
case XRT_LAYER_CYLINDER:
464
rgba = do_cylinder(view_uv, layer);
465
break;
466
-
case XRT_LAYER_EQUIRECT2:
467
rgba = do_equirect2(view_uv, layer);
468
break;
469
-
case XRT_LAYER_PROJECTION:
470
-
case XRT_LAYER_PROJECTION_DEPTH:
471
rgba = do_projection(view_uv, layer);
472
break;
473
-
case XRT_LAYER_QUAD:
474
-
rgba = do_quad(view_uv, layer);
475
-
break;
476
default: break;
477
}
478
479
-
if (ubo.layer_type_and_unpremultiplied[layer].y != 0) {
480
// Unpremultipled blend factor of src.a.
481
accum.rgb = mix(accum.rgb, rgba.rgb, rgba.a);
482
} else {
···
1
// Copyright 2021-2023, Collabora Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// Author: Jakob Bornecrantz <jakob@collabora.com>
4
// Author: Christoph Haag <christoph.haag@collabora.com>
5
// SPDX-License-Identifier: BSL-1.0
···
8
#extension GL_GOOGLE_include_directive : require
9
10
#include "srgb.inc.glsl"
11
+
#include "layer_defines.inc.glsl"
12
+
13
+
14
+
struct layer_data
15
+
{
16
+
uint layer_type;
17
+
uint unpremultiplied_alpha;
18
19
+
// This struct is used in an array, gets padded to vec4.
20
+
uint _padding0;
21
+
uint _padding1;
22
+
};
23
+
24
+
struct image_info
25
+
{
26
+
uint color_image_index;
27
+
uint depth_image_index;
28
+
29
+
// This struct is used in an array, gets padded to vec4.
30
+
uint _padding0;
31
+
uint _padding1;
32
+
};
33
+
34
35
const float PI = acos(-1);
36
···
55
vec4 pre_transform;
56
vec4 post_transform[RENDER_MAX_LAYERS];
57
58
+
// Per-layer data.
59
+
layer_data layer_data[RENDER_MAX_LAYERS];
60
61
// which image/sampler(s) correspond to each layer
62
+
image_info image_info[RENDER_MAX_LAYERS];
63
64
// shared between cylinder and equirect2
65
mat4 mv_inverse[RENDER_MAX_LAYERS];
···
241
242
vec2 uv_sub = fma(sample_point, ubo.post_transform[layer].zw, ubo.post_transform[layer].xy);
243
244
+
uint index = ubo.image_info[layer].color_image_index;
245
#ifdef DEBUG
246
out_color += texture(source[index], uv_sub) / 2.f;
247
#else
···
340
341
vec2 uv_sub = fma(sample_point, ubo.post_transform[layer].zw, ubo.post_transform[layer].xy);
342
343
+
uint index = ubo.image_info[layer].color_image_index;
344
#ifdef DEBUG
345
out_color += texture(source[index], uv_sub) / 2.0;
346
#else
···
356
357
vec4 do_projection(vec2 view_uv, uint layer)
358
{
359
+
uint source_image_index = ubo.image_info[layer].color_image_index;
360
361
// Do any transformation needed.
362
vec2 uv = transform_uv(view_uv, layer);
···
388
389
vec4 do_quad(vec2 view_uv, uint layer)
390
{
391
+
uint source_image_index = ubo.image_info[layer].color_image_index;
392
393
// center point of the plane in view space.
394
vec3 quad_position = ubo.quad_position[layer].xyz;
···
474
for (uint layer = 0; layer < layer_count; layer++) {
475
vec4 rgba = vec4(0, 0, 0, 0);
476
477
+
switch (ubo.layer_data[layer].layer_type) {
478
+
case LAYER_COMP_TYPE_QUAD:
479
+
rgba = do_quad(view_uv, layer);
480
+
break;
481
+
case LAYER_COMP_TYPE_CYLINDER:
482
rgba = do_cylinder(view_uv, layer);
483
break;
484
+
case LAYER_COMP_TYPE_EQUIRECT2:
485
rgba = do_equirect2(view_uv, layer);
486
break;
487
+
case LAYER_COMP_TYPE_PROJECTION:
488
rgba = do_projection(view_uv, layer);
489
break;
490
default: break;
491
}
492
493
+
if (ubo.layer_data[layer].unpremultiplied_alpha != 0) {
494
// Unpremultipled blend factor of src.a.
495
accum.rgb = mix(accum.rgb, rgba.rgb, rgba.a);
496
} else {
+22
src/xrt/compositor/shaders/layer_defines.inc.glsl
+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
+32
-9
src/xrt/compositor/util/comp_render_cs.c
···
26
27
#include "render/render_interface.h"
28
29
#include "util/comp_render.h"
30
#include "util/comp_render_helpers.h"
31
#include "util/comp_base.h"
···
33
34
/*
35
*
36
-
* Compute layer data builders.
37
*
38
*/
39
···
54
return &sc->images[image_index];
55
}
56
57
/// Data setup for a cylinder layer
58
static inline void
59
do_cs_cylinder_layer(const struct comp_layer *layer,
···
113
ubo_data->cylinder_data[cur_layer].central_angle = c->central_angle;
114
ubo_data->cylinder_data[cur_layer].aspect_ratio = c->aspect_ratio;
115
116
-
ubo_data->images_samplers[cur_layer].images[0] = cur_image;
117
cur_image++;
118
119
*out_cur_image = cur_image;
···
176
ubo_data->eq2_data[cur_layer].upper_vertical_angle = eq2->upper_vertical_angle;
177
ubo_data->eq2_data[cur_layer].lower_vertical_angle = eq2->lower_vertical_angle;
178
179
-
ubo_data->images_samplers[cur_layer].images[0] = cur_image;
180
cur_image++;
181
182
*out_cur_image = cur_image;
···
214
// Color
215
src_samplers[cur_image] = clamp_to_border_black;
216
src_image_views[cur_image] = get_image_view(image, layer_data->flags, array_index);
217
-
ubo_data->images_samplers[cur_layer + 0].images[0] = cur_image++;
218
219
// Depth
220
if (layer_data->type == XRT_LAYER_PROJECTION_DEPTH) {
···
224
225
src_samplers[cur_image] = clamp_to_edge; // Edge to keep depth stable at edges.
226
src_image_views[cur_image] = get_image_view(d_image, layer_data->flags, d_array_index);
227
-
ubo_data->images_samplers[cur_layer + 0].images[1] = cur_image++;
228
}
229
230
set_post_transform_rect( //
···
323
ubo_data->quad_position[cur_layer].val = quad_position;
324
ubo_data->quad_normal[cur_layer].val = normal_view_space;
325
ubo_data->inverse_quad_transform[cur_layer] = inverse_quad_transform;
326
-
ubo_data->images_samplers[cur_layer].images[0] = cur_image;
327
cur_image++;
328
329
*out_cur_image = cur_image;
···
660
continue;
661
}
662
663
-
ubo_data->layer_type[cur_layer].val = data->type;
664
-
ubo_data->layer_type[cur_layer].unpremultiplied = is_layer_unpremultiplied(data);
665
666
// Finally okay to increment the current layer.
667
cur_layer++;
···
671
ubo_data->layer_count.value = cur_layer;
672
673
for (uint32_t i = cur_layer; i < RENDER_MAX_LAYERS; i++) {
674
-
ubo_data->layer_type[i].val = UINT32_MAX;
675
}
676
677
//! @todo: If Vulkan 1.2, use VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT and skip this
···
26
27
#include "render/render_interface.h"
28
29
+
#include "shaders/layer_defines.inc.glsl"
30
+
31
#include "util/comp_render.h"
32
#include "util/comp_render_helpers.h"
33
#include "util/comp_base.h"
···
35
36
/*
37
*
38
+
* Helpers
39
*
40
*/
41
···
56
return &sc->images[image_index];
57
}
58
59
+
60
+
static inline uint32_t
61
+
xrt_layer_to_cs_layer_type(const struct xrt_layer_data *data)
62
+
{
63
+
switch (data->type) {
64
+
case XRT_LAYER_QUAD: return LAYER_COMP_TYPE_QUAD;
65
+
case XRT_LAYER_CYLINDER: return LAYER_COMP_TYPE_CYLINDER;
66
+
case XRT_LAYER_EQUIRECT2: return LAYER_COMP_TYPE_EQUIRECT2;
67
+
case XRT_LAYER_PROJECTION:
68
+
case XRT_LAYER_PROJECTION_DEPTH: return LAYER_COMP_TYPE_PROJECTION;
69
+
default: U_LOG_E("Invalid layer type! %u", data->type); return LAYER_COMP_TYPE_NOOP;
70
+
}
71
+
}
72
+
73
+
74
+
/*
75
+
*
76
+
* Compute layer data builders.
77
+
*
78
+
*/
79
+
80
/// Data setup for a cylinder layer
81
static inline void
82
do_cs_cylinder_layer(const struct comp_layer *layer,
···
136
ubo_data->cylinder_data[cur_layer].central_angle = c->central_angle;
137
ubo_data->cylinder_data[cur_layer].aspect_ratio = c->aspect_ratio;
138
139
+
ubo_data->image_info[cur_layer].color_image_index = cur_image;
140
cur_image++;
141
142
*out_cur_image = cur_image;
···
199
ubo_data->eq2_data[cur_layer].upper_vertical_angle = eq2->upper_vertical_angle;
200
ubo_data->eq2_data[cur_layer].lower_vertical_angle = eq2->lower_vertical_angle;
201
202
+
ubo_data->image_info[cur_layer].color_image_index = cur_image;
203
cur_image++;
204
205
*out_cur_image = cur_image;
···
237
// Color
238
src_samplers[cur_image] = clamp_to_border_black;
239
src_image_views[cur_image] = get_image_view(image, layer_data->flags, array_index);
240
+
ubo_data->image_info[cur_layer + 0].color_image_index = cur_image++;
241
242
// Depth
243
if (layer_data->type == XRT_LAYER_PROJECTION_DEPTH) {
···
247
248
src_samplers[cur_image] = clamp_to_edge; // Edge to keep depth stable at edges.
249
src_image_views[cur_image] = get_image_view(d_image, layer_data->flags, d_array_index);
250
+
ubo_data->image_info[cur_layer + 0].depth_image_index = cur_image++;
251
}
252
253
set_post_transform_rect( //
···
346
ubo_data->quad_position[cur_layer].val = quad_position;
347
ubo_data->quad_normal[cur_layer].val = normal_view_space;
348
ubo_data->inverse_quad_transform[cur_layer] = inverse_quad_transform;
349
+
ubo_data->image_info[cur_layer].color_image_index = cur_image;
350
cur_image++;
351
352
*out_cur_image = cur_image;
···
683
continue;
684
}
685
686
+
ubo_data->layer_data[cur_layer].layer_type = xrt_layer_to_cs_layer_type(data);
687
+
ubo_data->layer_data[cur_layer].unpremultiplied_alpha = is_layer_unpremultiplied(data);
688
689
// Finally okay to increment the current layer.
690
cur_layer++;
···
694
ubo_data->layer_count.value = cur_layer;
695
696
for (uint32_t i = cur_layer; i < RENDER_MAX_LAYERS; i++) {
697
+
ubo_data->layer_data[i].layer_type = LAYER_COMP_TYPE_NOOP; // Explicit no-op.
698
}
699
700
//! @todo: If Vulkan 1.2, use VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT and skip this
+3
-1
src/xrt/compositor/util/comp_swapchain.c
+3
-1
src/xrt/compositor/util/comp_swapchain.c
···
41
{
42
struct comp_swapchain *sc = comp_swapchain(xsc);
43
44
-
VK_TRACE(sc->vk, "DESTROY");
45
46
u_threading_stack_push(&sc->cscs->destroy_swapchains, sc);
47
}
···
476
static void
477
really_destroy(struct comp_swapchain *sc)
478
{
479
// Reuse close function.
480
comp_swapchain_teardown(sc);
481
···
41
{
42
struct comp_swapchain *sc = comp_swapchain(xsc);
43
44
+
VK_DEBUG(sc->vk, "%p DESTROY(not-actual)", (void *)sc);
45
46
u_threading_stack_push(&sc->cscs->destroy_swapchains, sc);
47
}
···
476
static void
477
really_destroy(struct comp_swapchain *sc)
478
{
479
+
VK_DEBUG(sc->vk, "%p REALLY_DESTROY", (void *)sc);
480
+
481
// Reuse close function.
482
comp_swapchain_teardown(sc);
483
+1
-6
src/xrt/drivers/android/android_sensors.c
+1
-6
src/xrt/drivers/android/android_sensors.c
···
133
args->tray_to_lens_distance_meters = params.tray_to_lens_distance;
134
}
135
136
-
#define DEG_TO_RAD(x) (float)(x * M_PI / 180.0)
137
args->fov = (struct xrt_fov){.angle_left = -DEG_TO_RAD(angles[0]),
138
.angle_right = DEG_TO_RAD(angles[1]),
139
.angle_down = -DEG_TO_RAD(angles[2]),
140
.angle_up = DEG_TO_RAD(angles[3])};
141
-
#undef DEG_TO_RAD
142
143
ANDROID_INFO(d, "loaded calibration for device %s (%s)", model, vendor);
144
···
354
struct android_device *d = U_DEVICE_ALLOCATE(struct android_device, flags, 1, 0);
355
356
d->base.name = XRT_DEVICE_GENERIC_HMD;
357
-
d->base.destroy = android_device_destroy;
358
-
d->base.update_inputs = u_device_noop_update_inputs;
359
-
d->base.set_output = u_device_ni_set_output;
360
-
d->base.get_tracked_pose = android_device_get_tracked_pose;
361
d->base.get_view_poses = u_device_get_view_poses;
362
d->base.get_visibility_mask = u_device_get_visibility_mask;
363
d->base.compute_distortion = android_device_compute_distortion;
···
133
args->tray_to_lens_distance_meters = params.tray_to_lens_distance;
134
}
135
136
args->fov = (struct xrt_fov){.angle_left = -DEG_TO_RAD(angles[0]),
137
.angle_right = DEG_TO_RAD(angles[1]),
138
.angle_down = -DEG_TO_RAD(angles[2]),
139
.angle_up = DEG_TO_RAD(angles[3])};
140
141
ANDROID_INFO(d, "loaded calibration for device %s (%s)", model, vendor);
142
···
352
struct android_device *d = U_DEVICE_ALLOCATE(struct android_device, flags, 1, 0);
353
354
d->base.name = XRT_DEVICE_GENERIC_HMD;
355
+
u_device_populate_function_pointers(&d->base, android_device_get_tracked_pose, android_device_destroy);
356
d->base.get_view_poses = u_device_get_view_poses;
357
d->base.get_visibility_mask = u_device_get_visibility_mask;
358
d->base.compute_distortion = android_device_compute_distortion;
+2
-2
src/xrt/drivers/arduino/arduino_device.c
+2
-2
src/xrt/drivers/arduino/arduino_device.c
···
405
406
m_imu_3dof_init(&ad->fusion, M_IMU_3DOF_USE_GRAVITY_DUR_300MS);
407
408
-
#define DEG_TO_RAD ((double)M_PI / 180.0)
409
float accel_ticks_to_float = (4.0 * MATH_GRAVITY_M_S2) / INT16_MAX;
410
-
float gyro_ticks_to_float = (2000.0 * DEG_TO_RAD) / INT16_MAX;
411
412
m_imu_pre_filter_init(&ad->pre_filter, accel_ticks_to_float, gyro_ticks_to_float);
413
m_imu_pre_filter_set_switch_x_and_y(&ad->pre_filter);
···
405
406
m_imu_3dof_init(&ad->fusion, M_IMU_3DOF_USE_GRAVITY_DUR_300MS);
407
408
+
#define DEG_TO_RAD_MULTIPLIER ((double)M_PI / 180.0)
409
float accel_ticks_to_float = (4.0 * MATH_GRAVITY_M_S2) / INT16_MAX;
410
+
float gyro_ticks_to_float = (2000.0 * DEG_TO_RAD_MULTIPLIER) / INT16_MAX;
411
412
m_imu_pre_filter_init(&ad->pre_filter, accel_ticks_to_float, gyro_ticks_to_float);
413
m_imu_pre_filter_set_switch_x_and_y(&ad->pre_filter);
+10
-2
src/xrt/drivers/blubur_s1/blubur_s1_hmd.c
+10
-2
src/xrt/drivers/blubur_s1/blubur_s1_hmd.c
···
157
blubur_s1_hmd_get_view_poses(struct xrt_device *xdev,
158
const struct xrt_vec3 *default_eye_relation,
159
int64_t at_timestamp_ns,
160
uint32_t view_count,
161
struct xrt_space_relation *out_head_relation,
162
struct xrt_fov *out_fovs,
163
struct xrt_pose *out_poses)
164
{
165
-
return u_device_get_view_poses(xdev, default_eye_relation, at_timestamp_ns, view_count, out_head_relation,
166
-
out_fovs, out_poses);
167
}
168
169
static void
···
157
blubur_s1_hmd_get_view_poses(struct xrt_device *xdev,
158
const struct xrt_vec3 *default_eye_relation,
159
int64_t at_timestamp_ns,
160
+
enum xrt_view_type view_type,
161
uint32_t view_count,
162
struct xrt_space_relation *out_head_relation,
163
struct xrt_fov *out_fovs,
164
struct xrt_pose *out_poses)
165
{
166
+
return u_device_get_view_poses( //
167
+
xdev, //
168
+
default_eye_relation, //
169
+
at_timestamp_ns, //
170
+
view_type, //
171
+
view_count, //
172
+
out_head_relation, //
173
+
out_fovs, //
174
+
out_poses); //
175
}
176
177
static void
+1
-5
src/xrt/drivers/euroc/euroc_device.c
+1
-5
src/xrt/drivers/euroc/euroc_device.c
···
206
xd->inputs[0].name = XRT_INPUT_SIMPLE_GRIP_POSE;
207
}
208
209
-
xd->update_inputs = u_device_noop_update_inputs;
210
-
xd->get_tracked_pose = euroc_device_get_tracked_pose;
211
-
xd->destroy = euroc_device_destroy;
212
if (is_hmd) {
213
xd->get_view_poses = u_device_get_view_poses;
214
-
} else {
215
-
xd->get_view_poses = u_device_ni_get_view_poses;
216
}
217
218
u_var_add_root(ed, dev_name, false);
+37
-19
src/xrt/drivers/ht_ctrl_emu/ht_ctrl_emu.cpp
+37
-19
src/xrt/drivers/ht_ctrl_emu/ht_ctrl_emu.cpp
···
1
// Copyright 2021, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
45
enum cemu_input_index
46
{
47
CEMU_INDEX_HAND_TRACKING,
48
-
CEMU_INDEX_SELECT,
49
-
CEMU_INDEX_MENU,
50
CEMU_INDEX_GRIP,
51
CEMU_INDEX_AIM,
52
CEMU_NUM_INPUTS,
···
372
struct cemu_device *dev = cemu_device(xdev);
373
struct cemu_system *sys = dev->sys;
374
375
-
if (name != XRT_INPUT_SIMPLE_GRIP_POSE && name != XRT_INPUT_SIMPLE_AIM_POSE) {
376
U_LOG_XDEV_UNSUPPORTED_INPUT(&dev->base, dev->sys->log_level, name);
377
return XRT_ERROR_INPUT_UNSUPPORTED;
378
}
···
390
391
xret = XRT_SUCCESS;
392
switch (name) {
393
-
case XRT_INPUT_SIMPLE_GRIP_POSE: {
394
xret = do_grip_pose(&joint_set, out_relation, sys->grip_offset_from_palm, dev->hand_index);
395
break;
396
}
397
-
case XRT_INPUT_SIMPLE_AIM_POSE: {
398
// Assume that now we're doing everything in the timestamp from the hand-tracker, so use
399
// hand_timestamp_ns. This will cause the controller to lag behind but otherwise be correct
400
xret = do_aim_pose(dev, &joint_set, at_timestamp_ns, hand_timestamp_ns, out_relation);
···
435
U_LOG_CHK_AND_RET(sys->log_level, xret, "xrt_device_get_hand_tracking");
436
437
if (!joint_set.is_active) {
438
-
xdev->inputs[CEMU_INDEX_SELECT].value.boolean = false;
439
-
xdev->inputs[CEMU_INDEX_MENU].value.boolean = false;
440
return XRT_SUCCESS;
441
}
442
443
decide(joint_set.values.hand_joint_set_default[XRT_HAND_JOINT_INDEX_TIP].relation.pose.position,
444
joint_set.values.hand_joint_set_default[XRT_HAND_JOINT_THUMB_TIP].relation.pose.position,
445
-
&xdev->inputs[CEMU_INDEX_SELECT].value.boolean);
446
447
// For now, all other inputs are off - detecting any gestures more complicated than pinch is too unreliable for
448
// now.
449
-
xdev->inputs[CEMU_INDEX_MENU].value.boolean = false;
450
451
return XRT_SUCCESS;
452
}
453
454
455
extern "C" int
456
cemu_devices_create(struct xrt_device *head, struct xrt_device *hands, struct xrt_device **out_xdevs)
···
480
481
cemud[i]->base.tracking_origin = hands->tracking_origin;
482
483
-
cemud[i]->base.name = XRT_DEVICE_SIMPLE_CONTROLLER;
484
cemud[i]->base.supported.hand_tracking = true;
485
cemud[i]->base.supported.orientation_tracking = true;
486
cemud[i]->base.supported.position_tracking = true;
487
-
488
489
cemud[i]->base.inputs[CEMU_INDEX_HAND_TRACKING].name = ht_input_names[i];
490
-
cemud[i]->base.inputs[CEMU_INDEX_SELECT].name = XRT_INPUT_SIMPLE_SELECT_CLICK;
491
-
cemud[i]->base.inputs[CEMU_INDEX_MENU].name = XRT_INPUT_SIMPLE_MENU_CLICK;
492
-
cemud[i]->base.inputs[CEMU_INDEX_GRIP].name = XRT_INPUT_SIMPLE_GRIP_POSE;
493
-
cemud[i]->base.inputs[CEMU_INDEX_AIM].name = XRT_INPUT_SIMPLE_AIM_POSE;
494
495
cemud[i]->base.update_inputs = cemu_device_update_inputs;
496
-
cemud[i]->base.get_tracked_pose = cemu_device_get_tracked_pose;
497
-
cemud[i]->base.set_output = u_device_ni_set_output;
498
cemud[i]->base.get_hand_tracking = cemu_device_get_hand_tracking;
499
-
cemud[i]->base.destroy = cemu_device_destroy;
500
501
cemud[i]->base.device_type =
502
i ? XRT_DEVICE_TYPE_RIGHT_HAND_CONTROLLER : XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER;
···
513
}
514
515
cemud[i]->ht_input_name = ht_input_names[i];
516
-
517
cemud[i]->hand_index = i;
518
system->out_hand[i] = cemud[i];
519
···
1
// Copyright 2021, Collabora, Ltd.
2
+
// Copyright 2024-2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
46
enum cemu_input_index
47
{
48
CEMU_INDEX_HAND_TRACKING,
49
+
CEMU_INDEX_PINCH_BOOL,
50
+
CEMU_INDEX_PINCH_FLOAT,
51
CEMU_INDEX_GRIP,
52
CEMU_INDEX_AIM,
53
CEMU_NUM_INPUTS,
···
373
struct cemu_device *dev = cemu_device(xdev);
374
struct cemu_system *sys = dev->sys;
375
376
+
if (name != XRT_INPUT_HAND_CTRL_EMU_AIM_POSE && name != XRT_INPUT_HAND_CTRL_EMU_GRIP_POSE) {
377
U_LOG_XDEV_UNSUPPORTED_INPUT(&dev->base, dev->sys->log_level, name);
378
return XRT_ERROR_INPUT_UNSUPPORTED;
379
}
···
391
392
xret = XRT_SUCCESS;
393
switch (name) {
394
+
case XRT_INPUT_HAND_CTRL_EMU_GRIP_POSE: {
395
xret = do_grip_pose(&joint_set, out_relation, sys->grip_offset_from_palm, dev->hand_index);
396
break;
397
}
398
+
case XRT_INPUT_HAND_CTRL_EMU_AIM_POSE: {
399
// Assume that now we're doing everything in the timestamp from the hand-tracker, so use
400
// hand_timestamp_ns. This will cause the controller to lag behind but otherwise be correct
401
xret = do_aim_pose(dev, &joint_set, at_timestamp_ns, hand_timestamp_ns, out_relation);
···
436
U_LOG_CHK_AND_RET(sys->log_level, xret, "xrt_device_get_hand_tracking");
437
438
if (!joint_set.is_active) {
439
+
xdev->inputs[CEMU_INDEX_PINCH_BOOL].value.boolean = false;
440
+
xdev->inputs[CEMU_INDEX_PINCH_FLOAT].value.vec1.x = 0.f;
441
return XRT_SUCCESS;
442
}
443
444
decide(joint_set.values.hand_joint_set_default[XRT_HAND_JOINT_INDEX_TIP].relation.pose.position,
445
joint_set.values.hand_joint_set_default[XRT_HAND_JOINT_THUMB_TIP].relation.pose.position,
446
+
&xdev->inputs[CEMU_INDEX_PINCH_BOOL].value.boolean);
447
448
// For now, all other inputs are off - detecting any gestures more complicated than pinch is too unreliable for
449
// now.
450
+
if (xdev->inputs[CEMU_INDEX_PINCH_BOOL].value.boolean) {
451
+
xdev->inputs[CEMU_INDEX_PINCH_FLOAT].value.vec1.x = 1.0f;
452
+
} else {
453
+
xdev->inputs[CEMU_INDEX_PINCH_FLOAT].value.vec1.x = 0.0f;
454
+
}
455
456
return XRT_SUCCESS;
457
}
458
459
+
static struct xrt_binding_input_pair simple_inputs[3] = {
460
+
{XRT_INPUT_SIMPLE_SELECT_CLICK, XRT_INPUT_HAND_CTRL_EMU_PINCH_BOOL},
461
+
{XRT_INPUT_SIMPLE_GRIP_POSE, XRT_INPUT_HAND_CTRL_EMU_GRIP_POSE},
462
+
{XRT_INPUT_SIMPLE_AIM_POSE, XRT_INPUT_HAND_CTRL_EMU_AIM_POSE},
463
+
};
464
+
465
+
static struct xrt_binding_profile binding_profiles[1] = {
466
+
{
467
+
.name = XRT_DEVICE_SIMPLE_CONTROLLER,
468
+
.inputs = simple_inputs,
469
+
.input_count = ARRAY_SIZE(simple_inputs),
470
+
.outputs = nullptr,
471
+
.output_count = 0,
472
+
},
473
+
};
474
475
extern "C" int
476
cemu_devices_create(struct xrt_device *head, struct xrt_device *hands, struct xrt_device **out_xdevs)
···
500
501
cemud[i]->base.tracking_origin = hands->tracking_origin;
502
503
+
cemud[i]->base.name = XRT_DEVICE_HAND_CTRL_EMU;
504
cemud[i]->base.supported.hand_tracking = true;
505
cemud[i]->base.supported.orientation_tracking = true;
506
cemud[i]->base.supported.position_tracking = true;
507
+
cemud[i]->base.binding_profiles = binding_profiles;
508
+
cemud[i]->base.binding_profile_count = ARRAY_SIZE(binding_profiles);
509
510
cemud[i]->base.inputs[CEMU_INDEX_HAND_TRACKING].name = ht_input_names[i];
511
+
cemud[i]->base.inputs[CEMU_INDEX_PINCH_BOOL].name = XRT_INPUT_HAND_CTRL_EMU_PINCH_BOOL;
512
+
cemud[i]->base.inputs[CEMU_INDEX_PINCH_FLOAT].name = XRT_INPUT_HAND_CTRL_EMU_PINCH_VALUE;
513
+
cemud[i]->base.inputs[CEMU_INDEX_GRIP].name = XRT_INPUT_HAND_CTRL_EMU_GRIP_POSE;
514
+
cemud[i]->base.inputs[CEMU_INDEX_AIM].name = XRT_INPUT_HAND_CTRL_EMU_AIM_POSE;
515
516
+
u_device_populate_function_pointers(&cemud[i]->base, cemu_device_get_tracked_pose, cemu_device_destroy);
517
cemud[i]->base.update_inputs = cemu_device_update_inputs;
518
cemud[i]->base.get_hand_tracking = cemu_device_get_hand_tracking;
519
520
cemud[i]->base.device_type =
521
i ? XRT_DEVICE_TYPE_RIGHT_HAND_CONTROLLER : XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER;
···
532
}
533
534
cemud[i]->ht_input_name = ht_input_names[i];
535
cemud[i]->hand_index = i;
536
system->out_hand[i] = cemud[i];
537
+2
-6
src/xrt/drivers/hydra/hydra_driver.c
+2
-6
src/xrt/drivers/hydra/hydra_driver.c
···
345
(XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT | XRT_SPACE_RELATION_ORIENTATION_VALID_BIT) |
346
(XRT_SPACE_RELATION_POSITION_TRACKED_BIT | XRT_SPACE_RELATION_POSITION_VALID_BIT);
347
348
-
m_relation_history_estimate_motion(state->relation_history, &space_relation, now, &space_relation);
349
-
350
-
m_relation_history_push(state->relation_history, &space_relation, now);
351
352
state->buttons = hydra_read_uint8(&buf);
353
···
799
for (size_t i = 0; i < 2; ++i) {
800
struct hydra_device *hd = hs->devs[i];
801
802
-
hd->base.destroy = hydra_device_destroy;
803
hd->base.update_inputs = hydra_device_update_inputs;
804
-
hd->base.get_tracked_pose = hydra_device_get_tracked_pose;
805
-
hd->base.set_output = u_device_ni_set_output;
806
hd->base.name = XRT_DEVICE_HYDRA;
807
snprintf(hd->base.str, XRT_DEVICE_NAME_LEN, "%s %i", "Razer Hydra Controller", (int)(i + 1));
808
snprintf(hd->base.serial, XRT_DEVICE_NAME_LEN, "%s%i", "RZRHDRC", (int)(i + 1));
···
345
(XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT | XRT_SPACE_RELATION_ORIENTATION_VALID_BIT) |
346
(XRT_SPACE_RELATION_POSITION_TRACKED_BIT | XRT_SPACE_RELATION_POSITION_VALID_BIT);
347
348
+
m_relation_history_push_with_motion_estimation(state->relation_history, &space_relation, now);
349
350
state->buttons = hydra_read_uint8(&buf);
351
···
797
for (size_t i = 0; i < 2; ++i) {
798
struct hydra_device *hd = hs->devs[i];
799
800
+
u_device_populate_function_pointers(&hd->base, hydra_device_get_tracked_pose, hydra_device_destroy);
801
hd->base.update_inputs = hydra_device_update_inputs;
802
hd->base.name = XRT_DEVICE_HYDRA;
803
snprintf(hd->base.str, XRT_DEVICE_NAME_LEN, "%s %i", "Razer Hydra Controller", (int)(i + 1));
804
snprintf(hd->base.serial, XRT_DEVICE_NAME_LEN, "%s%i", "RZRHDRC", (int)(i + 1));
+11
-2
src/xrt/drivers/multi_wrapper/multi.c
+11
-2
src/xrt/drivers/multi_wrapper/multi.c
···
196
get_view_poses(struct xrt_device *xdev,
197
const struct xrt_vec3 *default_eye_relation,
198
int64_t at_timestamp_ns,
199
uint32_t view_count,
200
struct xrt_space_relation *out_head_relation,
201
struct xrt_fov *out_fovs,
···
203
{
204
struct multi_device *d = (struct multi_device *)xdev;
205
struct xrt_device *target = d->tracking_override.target;
206
-
xrt_result_t xret = xrt_device_get_view_poses(target, default_eye_relation, at_timestamp_ns, view_count,
207
-
out_head_relation, out_fovs, out_poses);
208
if (xret != XRT_SUCCESS) {
209
return xret;
210
}
···
196
get_view_poses(struct xrt_device *xdev,
197
const struct xrt_vec3 *default_eye_relation,
198
int64_t at_timestamp_ns,
199
+
enum xrt_view_type view_type,
200
uint32_t view_count,
201
struct xrt_space_relation *out_head_relation,
202
struct xrt_fov *out_fovs,
···
204
{
205
struct multi_device *d = (struct multi_device *)xdev;
206
struct xrt_device *target = d->tracking_override.target;
207
+
208
+
xrt_result_t xret = xrt_device_get_view_poses( //
209
+
target, //
210
+
default_eye_relation, //
211
+
at_timestamp_ns, //
212
+
view_type, //
213
+
view_count, //
214
+
out_head_relation, //
215
+
out_fovs, //
216
+
out_poses); //
217
if (xret != XRT_SUCCESS) {
218
return xret;
219
}
+2
src/xrt/drivers/north_star/ns_hmd.c
+2
src/xrt/drivers/north_star/ns_hmd.c
···
389
ns_hmd_get_view_poses(struct xrt_device *xdev,
390
const struct xrt_vec3 *default_eye_relation,
391
int64_t at_timestamp_ns,
392
uint32_t view_count,
393
struct xrt_space_relation *out_head_relation,
394
struct xrt_fov *out_fovs,
···
402
xdev, //
403
default_eye_relation, //
404
at_timestamp_ns, //
405
view_count, //
406
out_head_relation, //
407
out_fovs, //
···
389
ns_hmd_get_view_poses(struct xrt_device *xdev,
390
const struct xrt_vec3 *default_eye_relation,
391
int64_t at_timestamp_ns,
392
+
enum xrt_view_type view_type,
393
uint32_t view_count,
394
struct xrt_space_relation *out_head_relation,
395
struct xrt_fov *out_fovs,
···
403
xdev, //
404
default_eye_relation, //
405
at_timestamp_ns, //
406
+
view_type, //
407
view_count, //
408
out_head_relation, //
409
out_fovs, //
+2
-5
src/xrt/drivers/ohmd/oh_device.c
+2
-5
src/xrt/drivers/ohmd/oh_device.c
···
757
758
enum u_device_alloc_flags flags = U_DEVICE_ALLOC_HMD;
759
struct oh_device *ohd = U_DEVICE_ALLOCATE(struct oh_device, flags, 1, 0);
760
ohd->base.update_inputs = oh_device_update_inputs;
761
-
ohd->base.get_tracked_pose = oh_device_get_tracked_pose;
762
ohd->base.get_view_poses = u_device_get_view_poses;
763
-
ohd->base.destroy = oh_device_destroy;
764
ohd->base.inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE;
765
ohd->base.name = XRT_DEVICE_GENERIC_HMD;
766
ohd->ctx = ctx;
···
1074
1075
enum u_device_alloc_flags flags = 0;
1076
struct oh_device *ohd = U_DEVICE_ALLOCATE(struct oh_device, flags, input_count, output_count);
1077
ohd->base.update_inputs = oh_device_update_inputs;
1078
ohd->base.set_output = oh_device_set_output;
1079
-
ohd->base.get_tracked_pose = oh_device_get_tracked_pose;
1080
-
ohd->base.get_view_poses = u_device_ni_get_view_poses;
1081
-
ohd->base.destroy = oh_device_destroy;
1082
if (oculus_touch) {
1083
ohd->ohmd_device_type = OPENHMD_OCULUS_RIFT_CONTROLLER;
1084
ohd->base.name = XRT_DEVICE_TOUCH_CONTROLLER;
···
757
758
enum u_device_alloc_flags flags = U_DEVICE_ALLOC_HMD;
759
struct oh_device *ohd = U_DEVICE_ALLOCATE(struct oh_device, flags, 1, 0);
760
+
u_device_populate_function_pointers(&ohd->base, oh_device_get_tracked_pose, oh_device_destroy);
761
ohd->base.update_inputs = oh_device_update_inputs;
762
ohd->base.get_view_poses = u_device_get_view_poses;
763
ohd->base.inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE;
764
ohd->base.name = XRT_DEVICE_GENERIC_HMD;
765
ohd->ctx = ctx;
···
1073
1074
enum u_device_alloc_flags flags = 0;
1075
struct oh_device *ohd = U_DEVICE_ALLOCATE(struct oh_device, flags, input_count, output_count);
1076
+
u_device_populate_function_pointers(&ohd->base, oh_device_get_tracked_pose, oh_device_destroy);
1077
ohd->base.update_inputs = oh_device_update_inputs;
1078
ohd->base.set_output = oh_device_set_output;
1079
if (oculus_touch) {
1080
ohd->ohmd_device_type = OPENHMD_OCULUS_RIFT_CONTROLLER;
1081
ohd->base.name = XRT_DEVICE_TOUCH_CONTROLLER;
+6
-8
src/xrt/drivers/pssense/pssense_driver.c
+6
-8
src/xrt/drivers/pssense/pssense_driver.c
···
43
44
DEBUG_GET_ONCE_LOG_OPTION(pssense_log, "PSSENSE_LOG", U_LOGGING_INFO)
45
46
-
#define DEG_TO_RAD(DEG) (DEG * M_PI / 180.)
47
-
48
static struct xrt_binding_input_pair simple_inputs_pssense[4] = {
49
{XRT_INPUT_SIMPLE_SELECT_CLICK, XRT_INPUT_PSSENSE_TRIGGER_VALUE},
50
{XRT_INPUT_SIMPLE_MENU_CLICK, XRT_INPUT_PSSENSE_OPTIONS_CLICK},
···
84
PSSENSE_INDEX_CIRCLE_TOUCH,
85
PSSENSE_INDEX_SQUEEZE_CLICK,
86
PSSENSE_INDEX_SQUEEZE_TOUCH,
87
-
PSSENSE_INDEX_SQUEEZE_PROXIMITY,
88
PSSENSE_INDEX_TRIGGER_CLICK,
89
PSSENSE_INDEX_TRIGGER_TOUCH,
90
PSSENSE_INDEX_TRIGGER_VALUE,
91
-
PSSENSE_INDEX_TRIGGER_PROXIMITY,
92
PSSENSE_INDEX_THUMBSTICK,
93
PSSENSE_INDEX_THUMBSTICK_CLICK,
94
PSSENSE_INDEX_THUMBSTICK_TOUCH,
···
661
pssense->base.inputs[PSSENSE_INDEX_CIRCLE_TOUCH].value.boolean = pssense->state.circle_touch;
662
pssense->base.inputs[PSSENSE_INDEX_SQUEEZE_CLICK].value.boolean = pssense->state.squeeze_click;
663
pssense->base.inputs[PSSENSE_INDEX_SQUEEZE_TOUCH].value.boolean = pssense->state.squeeze_touch;
664
-
pssense->base.inputs[PSSENSE_INDEX_SQUEEZE_PROXIMITY].value.vec1.x = pssense->state.squeeze_proximity;
665
pssense->base.inputs[PSSENSE_INDEX_TRIGGER_CLICK].value.boolean = pssense->state.trigger_click;
666
pssense->base.inputs[PSSENSE_INDEX_TRIGGER_TOUCH].value.boolean = pssense->state.trigger_touch;
667
pssense->base.inputs[PSSENSE_INDEX_TRIGGER_VALUE].value.vec1.x = pssense->state.trigger_value;
668
-
pssense->base.inputs[PSSENSE_INDEX_TRIGGER_PROXIMITY].value.vec1.x = pssense->state.trigger_proximity;
669
pssense->base.inputs[PSSENSE_INDEX_THUMBSTICK].value.vec2 = pssense->state.thumbstick;
670
pssense->base.inputs[PSSENSE_INDEX_THUMBSTICK_CLICK].value.boolean = pssense->state.thumbstick_click;
671
pssense->base.inputs[PSSENSE_INDEX_THUMBSTICK_TOUCH].value.boolean = pssense->state.thumbstick_touch;
···
933
SET_INPUT(CIRCLE_TOUCH);
934
SET_INPUT(SQUEEZE_CLICK);
935
SET_INPUT(SQUEEZE_TOUCH);
936
-
SET_INPUT(SQUEEZE_PROXIMITY);
937
SET_INPUT(TRIGGER_CLICK);
938
SET_INPUT(TRIGGER_TOUCH);
939
SET_INPUT(TRIGGER_VALUE);
940
-
SET_INPUT(TRIGGER_PROXIMITY);
941
SET_INPUT(THUMBSTICK);
942
SET_INPUT(THUMBSTICK_CLICK);
943
SET_INPUT(THUMBSTICK_TOUCH);
···
43
44
DEBUG_GET_ONCE_LOG_OPTION(pssense_log, "PSSENSE_LOG", U_LOGGING_INFO)
45
46
static struct xrt_binding_input_pair simple_inputs_pssense[4] = {
47
{XRT_INPUT_SIMPLE_SELECT_CLICK, XRT_INPUT_PSSENSE_TRIGGER_VALUE},
48
{XRT_INPUT_SIMPLE_MENU_CLICK, XRT_INPUT_PSSENSE_OPTIONS_CLICK},
···
82
PSSENSE_INDEX_CIRCLE_TOUCH,
83
PSSENSE_INDEX_SQUEEZE_CLICK,
84
PSSENSE_INDEX_SQUEEZE_TOUCH,
85
+
PSSENSE_INDEX_SQUEEZE_PROXIMITY_FLOAT,
86
PSSENSE_INDEX_TRIGGER_CLICK,
87
PSSENSE_INDEX_TRIGGER_TOUCH,
88
PSSENSE_INDEX_TRIGGER_VALUE,
89
+
PSSENSE_INDEX_TRIGGER_PROXIMITY_FLOAT,
90
PSSENSE_INDEX_THUMBSTICK,
91
PSSENSE_INDEX_THUMBSTICK_CLICK,
92
PSSENSE_INDEX_THUMBSTICK_TOUCH,
···
659
pssense->base.inputs[PSSENSE_INDEX_CIRCLE_TOUCH].value.boolean = pssense->state.circle_touch;
660
pssense->base.inputs[PSSENSE_INDEX_SQUEEZE_CLICK].value.boolean = pssense->state.squeeze_click;
661
pssense->base.inputs[PSSENSE_INDEX_SQUEEZE_TOUCH].value.boolean = pssense->state.squeeze_touch;
662
+
pssense->base.inputs[PSSENSE_INDEX_SQUEEZE_PROXIMITY_FLOAT].value.vec1.x = pssense->state.squeeze_proximity;
663
pssense->base.inputs[PSSENSE_INDEX_TRIGGER_CLICK].value.boolean = pssense->state.trigger_click;
664
pssense->base.inputs[PSSENSE_INDEX_TRIGGER_TOUCH].value.boolean = pssense->state.trigger_touch;
665
pssense->base.inputs[PSSENSE_INDEX_TRIGGER_VALUE].value.vec1.x = pssense->state.trigger_value;
666
+
pssense->base.inputs[PSSENSE_INDEX_TRIGGER_PROXIMITY_FLOAT].value.vec1.x = pssense->state.trigger_proximity;
667
pssense->base.inputs[PSSENSE_INDEX_THUMBSTICK].value.vec2 = pssense->state.thumbstick;
668
pssense->base.inputs[PSSENSE_INDEX_THUMBSTICK_CLICK].value.boolean = pssense->state.thumbstick_click;
669
pssense->base.inputs[PSSENSE_INDEX_THUMBSTICK_TOUCH].value.boolean = pssense->state.thumbstick_touch;
···
931
SET_INPUT(CIRCLE_TOUCH);
932
SET_INPUT(SQUEEZE_CLICK);
933
SET_INPUT(SQUEEZE_TOUCH);
934
+
SET_INPUT(SQUEEZE_PROXIMITY_FLOAT);
935
SET_INPUT(TRIGGER_CLICK);
936
SET_INPUT(TRIGGER_TOUCH);
937
SET_INPUT(TRIGGER_VALUE);
938
+
SET_INPUT(TRIGGER_PROXIMITY_FLOAT);
939
SET_INPUT(THUMBSTICK);
940
SET_INPUT(THUMBSTICK_CLICK);
941
SET_INPUT(THUMBSTICK_TOUCH);
+1
-4
src/xrt/drivers/realsense/rs_ddev.c
+1
-4
src/xrt/drivers/realsense/rs_ddev.c
···
448
449
U_LOG_D("Realsense opts are %i %i %i %i %i\n", rs->enable_mapping, rs->enable_pose_jumping,
450
rs->enable_relocalization, rs->enable_pose_prediction, rs->enable_pose_filtering);
451
-
rs->base.update_inputs = u_device_noop_update_inputs;
452
-
rs->base.get_tracked_pose = rs_ddev_get_tracked_pose;
453
-
rs->base.get_view_poses = u_device_ni_get_view_poses;
454
-
rs->base.destroy = rs_ddev_destroy;
455
rs->base.name = XRT_DEVICE_REALSENSE;
456
rs->base.tracking_origin->type = XRT_TRACKING_TYPE_EXTERNAL_SLAM;
457
···
448
449
U_LOG_D("Realsense opts are %i %i %i %i %i\n", rs->enable_mapping, rs->enable_pose_jumping,
450
rs->enable_relocalization, rs->enable_pose_prediction, rs->enable_pose_filtering);
451
+
u_device_populate_function_pointers(&rs->base, rs_ddev_get_tracked_pose, rs_ddev_destroy);
452
rs->base.name = XRT_DEVICE_REALSENSE;
453
rs->base.tracking_origin->type = XRT_TRACKING_TYPE_EXTERNAL_SLAM;
454
+1
-4
src/xrt/drivers/remote/r_device.c
+1
-4
src/xrt/drivers/remote/r_device.c
···
193
struct r_device, flags, input_count, output_count);
194
195
// Setup the basics.
196
rd->base.update_inputs = r_device_update_inputs;
197
-
rd->base.get_tracked_pose = r_device_get_tracked_pose;
198
rd->base.get_hand_tracking = r_device_get_hand_tracking;
199
-
rd->base.get_view_poses = u_device_ni_get_view_poses;
200
-
rd->base.set_output = u_device_ni_set_output;
201
-
rd->base.destroy = r_device_destroy;
202
rd->base.tracking_origin = &r->origin;
203
rd->base.supported.orientation_tracking = true;
204
rd->base.supported.position_tracking = true;
···
193
struct r_device, flags, input_count, output_count);
194
195
// Setup the basics.
196
+
u_device_populate_function_pointers(&rd->base, r_device_get_tracked_pose, r_device_destroy);
197
rd->base.update_inputs = r_device_update_inputs;
198
rd->base.get_hand_tracking = r_device_get_hand_tracking;
199
rd->base.tracking_origin = &r->origin;
200
rd->base.supported.orientation_tracking = true;
201
rd->base.supported.position_tracking = true;
+3
-5
src/xrt/drivers/remote/r_hmd.c
+3
-5
src/xrt/drivers/remote/r_hmd.c
···
78
r_hmd_get_view_poses(struct xrt_device *xdev,
79
const struct xrt_vec3 *default_eye_relation,
80
int64_t at_timestamp_ns,
81
uint32_t view_count,
82
struct xrt_space_relation *out_head_relation,
83
struct xrt_fov *out_fovs,
···
90
xdev, //
91
default_eye_relation, //
92
at_timestamp_ns, //
93
view_count, //
94
out_head_relation, //
95
out_fovs, //
···
122
struct r_hmd, flags, input_count, output_count);
123
124
// Setup the basics.
125
-
rh->base.update_inputs = u_device_noop_update_inputs;
126
-
rh->base.get_tracked_pose = r_hmd_get_tracked_pose;
127
-
rh->base.get_hand_tracking = u_device_ni_get_hand_tracking;
128
rh->base.get_view_poses = r_hmd_get_view_poses;
129
-
rh->base.set_output = u_device_ni_set_output;
130
-
rh->base.destroy = r_hmd_destroy;
131
rh->base.tracking_origin = &r->origin;
132
rh->base.supported.orientation_tracking = true;
133
rh->base.supported.position_tracking = true;
···
78
r_hmd_get_view_poses(struct xrt_device *xdev,
79
const struct xrt_vec3 *default_eye_relation,
80
int64_t at_timestamp_ns,
81
+
enum xrt_view_type view_type,
82
uint32_t view_count,
83
struct xrt_space_relation *out_head_relation,
84
struct xrt_fov *out_fovs,
···
91
xdev, //
92
default_eye_relation, //
93
at_timestamp_ns, //
94
+
view_type, //
95
view_count, //
96
out_head_relation, //
97
out_fovs, //
···
124
struct r_hmd, flags, input_count, output_count);
125
126
// Setup the basics.
127
+
u_device_populate_function_pointers(&rh->base, r_hmd_get_tracked_pose, r_hmd_destroy);
128
rh->base.get_view_poses = r_hmd_get_view_poses;
129
rh->base.tracking_origin = &r->origin;
130
rh->base.supported.orientation_tracking = true;
131
rh->base.supported.position_tracking = true;
+10
-7
src/xrt/drivers/rift/rift_hmd.c
+10
-7
src/xrt/drivers/rift/rift_hmd.c
···
230
rift_hmd_get_view_poses(struct xrt_device *xdev,
231
const struct xrt_vec3 *default_eye_relation,
232
int64_t at_timestamp_ns,
233
uint32_t view_count,
234
struct xrt_space_relation *out_head_relation,
235
struct xrt_fov *out_fovs,
···
237
{
238
struct rift_hmd *hmd = rift_hmd(xdev);
239
240
-
return u_device_get_view_poses(xdev, //
241
-
&(struct xrt_vec3){hmd->extra_display_info.icd, 0.0f, 0.0f}, //
242
-
at_timestamp_ns, //
243
-
view_count, //
244
-
out_head_relation, //
245
-
out_fovs, //
246
-
out_poses);
247
}
248
249
static xrt_result_t
···
230
rift_hmd_get_view_poses(struct xrt_device *xdev,
231
const struct xrt_vec3 *default_eye_relation,
232
int64_t at_timestamp_ns,
233
+
enum xrt_view_type view_type,
234
uint32_t view_count,
235
struct xrt_space_relation *out_head_relation,
236
struct xrt_fov *out_fovs,
···
238
{
239
struct rift_hmd *hmd = rift_hmd(xdev);
240
241
+
return u_device_get_view_poses( //
242
+
xdev, //
243
+
&(struct xrt_vec3){hmd->extra_display_info.icd, 0.0f, 0.0f}, //
244
+
at_timestamp_ns, //
245
+
view_type, //
246
+
view_count, //
247
+
out_head_relation, //
248
+
out_fovs, //
249
+
out_poses);
250
}
251
252
static xrt_result_t
-1
src/xrt/drivers/rift/rift_interface.h
-1
src/xrt/drivers/rift/rift_interface.h
+1
-5
src/xrt/drivers/rift_s/rift_s_controller.c
+1
-5
src/xrt/drivers/rift_s/rift_s_controller.c
···
40
/* Set to 1 to print controller states continuously */
41
#define DUMP_CONTROLLER_STATE 0
42
43
-
#define DEG_TO_RAD(D) ((D)*M_PI / 180.)
44
-
45
static struct xrt_binding_input_pair simple_inputs_rift_s[4] = {
46
{XRT_INPUT_SIMPLE_SELECT_CLICK, XRT_INPUT_TOUCH_TRIGGER_VALUE},
47
{XRT_INPUT_SIMPLE_MENU_CLICK, XRT_INPUT_TOUCH_MENU_CLICK},
···
606
607
os_mutex_init(&ctrl->mutex);
608
609
ctrl->base.update_inputs = rift_s_controller_update_inputs;
610
-
ctrl->base.set_output = u_device_ni_set_output;
611
-
ctrl->base.get_tracked_pose = rift_s_controller_get_tracked_pose;
612
ctrl->base.get_view_poses = u_device_get_view_poses;
613
-
ctrl->base.destroy = rift_s_controller_destroy;
614
ctrl->base.name = XRT_DEVICE_TOUCH_CONTROLLER;
615
ctrl->base.device_type = device_type;
616
···
40
/* Set to 1 to print controller states continuously */
41
#define DUMP_CONTROLLER_STATE 0
42
43
static struct xrt_binding_input_pair simple_inputs_rift_s[4] = {
44
{XRT_INPUT_SIMPLE_SELECT_CLICK, XRT_INPUT_TOUCH_TRIGGER_VALUE},
45
{XRT_INPUT_SIMPLE_MENU_CLICK, XRT_INPUT_TOUCH_MENU_CLICK},
···
604
605
os_mutex_init(&ctrl->mutex);
606
607
+
u_device_populate_function_pointers(&ctrl->base, rift_s_controller_get_tracked_pose, rift_s_controller_destroy);
608
ctrl->base.update_inputs = rift_s_controller_update_inputs;
609
ctrl->base.get_view_poses = u_device_get_view_poses;
610
ctrl->base.name = XRT_DEVICE_TOUCH_CONTROLLER;
611
ctrl->base.device_type = device_type;
612
-2
src/xrt/drivers/rift_s/rift_s_hmd.c
-2
src/xrt/drivers/rift_s/rift_s_hmd.c
+2
src/xrt/drivers/sample/sample_hmd.c
+2
src/xrt/drivers/sample/sample_hmd.c
···
132
sample_hmd_get_view_poses(struct xrt_device *xdev,
133
const struct xrt_vec3 *default_eye_relation,
134
int64_t at_timestamp_ns,
135
uint32_t view_count,
136
struct xrt_space_relation *out_head_relation,
137
struct xrt_fov *out_fovs,
···
145
xdev, //
146
default_eye_relation, //
147
at_timestamp_ns, //
148
view_count, //
149
out_head_relation, //
150
out_fovs, //
···
132
sample_hmd_get_view_poses(struct xrt_device *xdev,
133
const struct xrt_vec3 *default_eye_relation,
134
int64_t at_timestamp_ns,
135
+
enum xrt_view_type view_type,
136
uint32_t view_count,
137
struct xrt_space_relation *out_head_relation,
138
struct xrt_fov *out_fovs,
···
146
xdev, //
147
default_eye_relation, //
148
at_timestamp_ns, //
149
+
view_type, //
150
view_count, //
151
out_head_relation, //
152
out_fovs, //
+2
-2
src/xrt/drivers/simula/svr_hmd.c
+2
-2
src/xrt/drivers/simula/svr_hmd.c
···
97
return XRT_SUCCESS;
98
}
99
100
-
#define DEG_TO_RAD(DEG) (DEG * M_PI / 180.)
101
-
102
static xrt_result_t
103
svr_hmd_get_view_poses(struct xrt_device *xdev,
104
const struct xrt_vec3 *default_eye_relation,
105
int64_t at_timestamp_ns,
106
uint32_t view_count,
107
struct xrt_space_relation *out_head_relation,
108
struct xrt_fov *out_fovs,
···
115
xdev, //
116
default_eye_relation, //
117
at_timestamp_ns, //
118
view_count, //
119
out_head_relation, //
120
out_fovs, //
···
97
return XRT_SUCCESS;
98
}
99
100
static xrt_result_t
101
svr_hmd_get_view_poses(struct xrt_device *xdev,
102
const struct xrt_vec3 *default_eye_relation,
103
int64_t at_timestamp_ns,
104
+
enum xrt_view_type view_type,
105
uint32_t view_count,
106
struct xrt_space_relation *out_head_relation,
107
struct xrt_fov *out_fovs,
···
114
xdev, //
115
default_eye_relation, //
116
at_timestamp_ns, //
117
+
view_type, //
118
view_count, //
119
out_head_relation, //
120
out_fovs, //
+1
-5
src/xrt/drivers/simulated/simulated_controller.c
+1
-5
src/xrt/drivers/simulated/simulated_controller.c
···
347
348
// Allocate.
349
struct simulated_device *sd = U_DEVICE_ALLOCATE(struct simulated_device, flags, input_count, output_count);
350
sd->base.update_inputs = simulated_device_update_inputs;
351
-
sd->base.get_tracked_pose = simulated_device_get_tracked_pose;
352
-
sd->base.get_hand_tracking = u_device_ni_get_hand_tracking;
353
-
sd->base.get_view_poses = u_device_ni_get_view_poses;
354
-
sd->base.set_output = u_device_ni_set_output;
355
-
sd->base.destroy = simulated_device_destroy;
356
sd->base.tracking_origin = origin;
357
sd->base.supported.orientation_tracking = true;
358
sd->base.supported.position_tracking = true;
···
347
348
// Allocate.
349
struct simulated_device *sd = U_DEVICE_ALLOCATE(struct simulated_device, flags, input_count, output_count);
350
+
u_device_populate_function_pointers(&sd->base, simulated_device_get_tracked_pose, simulated_device_destroy);
351
sd->base.update_inputs = simulated_device_update_inputs;
352
sd->base.tracking_origin = origin;
353
sd->base.supported.orientation_tracking = true;
354
sd->base.supported.position_tracking = true;
+365
-101
src/xrt/drivers/steamvr_lh/device.cpp
+365
-101
src/xrt/drivers/steamvr_lh/device.cpp
···
9
*/
10
11
#include "math/m_api.h"
12
#include "math/m_relation_history.h"
13
#include "math/m_space.h"
14
···
16
17
#include "util/u_debug.h"
18
#include "util/u_device.h"
19
-
#include "util/u_hand_simulation.h"
20
#include "util/u_hand_tracking.h"
21
#include "util/u_logging.h"
22
#include "util/u_json.hpp"
23
24
#include "xrt/xrt_defines.h"
25
#include "xrt/xrt_device.h"
26
#include "xrt/xrt_prober.h"
···
34
#include <cmath>
35
#include <functional>
36
#include <cstring>
37
#include <thread>
38
#include <algorithm>
39
#include <map>
40
-
41
42
#define DEV_ERR(...) U_LOG_IFL_E(ctx->log_level, __VA_ARGS__)
43
#define DEV_WARN(...) U_LOG_IFL_W(ctx->log_level, __VA_ARGS__)
···
52
xrt_device_name name;
53
const std::vector<xrt_input_name> poses;
54
const std::unordered_map<std::string_view, xrt_input_name> non_poses;
55
-
const std::unordered_map<std::string_view, IndexFinger> finger_curls;
56
};
57
58
namespace {
59
// Adding support for a new controller is a simple as adding it here.
60
// The key for the map needs to be the name of input profile as indicated by the lighthouse driver.
61
const std::unordered_map<std::string_view, InputClass> controller_classes{
···
66
{
67
XRT_INPUT_VIVE_GRIP_POSE,
68
XRT_INPUT_VIVE_AIM_POSE,
69
},
70
{
71
{"/input/application_menu/click", XRT_INPUT_VIVE_MENU_CLICK},
···
76
{"/input/trigger/value", XRT_INPUT_VIVE_TRIGGER_VALUE},
77
{"/input/grip/click", XRT_INPUT_VIVE_SQUEEZE_CLICK},
78
{"/input/trackpad", XRT_INPUT_VIVE_TRACKPAD},
79
-
},
80
-
{
81
-
// No fingers on this controller type
82
},
83
},
84
},
···
89
{
90
XRT_INPUT_INDEX_GRIP_POSE,
91
XRT_INPUT_INDEX_AIM_POSE,
92
},
93
{
94
{"/input/system/click", XRT_INPUT_INDEX_SYSTEM_CLICK},
···
109
{"/input/trackpad/touch", XRT_INPUT_INDEX_TRACKPAD_TOUCH},
110
{"/input/trackpad", XRT_INPUT_INDEX_TRACKPAD},
111
},
112
-
{
113
-
{"/input/finger/index", IndexFinger::Index},
114
-
{"/input/finger/middle", IndexFinger::Middle},
115
-
{"/input/finger/ring", IndexFinger::Ring},
116
-
{"/input/finger/pinky", IndexFinger::Pinky},
117
-
},
118
},
119
},
120
{
···
130
{"/input/application_menu/click", XRT_INPUT_VIVE_TRACKER_MENU_CLICK},
131
{"/input/trigger/click", XRT_INPUT_VIVE_TRACKER_TRIGGER_CLICK},
132
{"/input/thumb/click", XRT_INPUT_VIVE_TRACKER_TRACKPAD_CLICK},
133
-
},
134
-
{
135
-
// No fingers on this controller type
136
},
137
},
138
},
···
150
{"/input/trigger/click", XRT_INPUT_VIVE_TRACKER_TRIGGER_CLICK},
151
{"/input/thumb/click", XRT_INPUT_VIVE_TRACKER_TRACKPAD_CLICK},
152
},
153
-
{
154
-
// No fingers on this controller type
155
-
},
156
},
157
},
158
};
159
-
160
int64_t
161
chrono_timestamp_ns()
162
{
···
214
215
return brightness;
216
}
217
} // namespace
218
219
Property::Property(vr::PropertyTypeTag_t tag, void *buffer, uint32_t bufferSize)
···
249
this->xrt_device::get_hand_tracking =
250
&device_bouncer<ControllerDevice, &ControllerDevice::get_hand_tracking, xrt_result_t>;
251
this->xrt_device::set_output = &device_bouncer<ControllerDevice, &ControllerDevice::set_output, xrt_result_t>;
252
}
253
254
Device::~Device()
···
285
init_chaperone(builder.steam_install);
286
}
287
288
-
void
289
-
ControllerDevice::set_hand_tracking_hand(xrt_input_name name)
290
-
{
291
-
if (has_index_hand_tracking) {
292
-
inputs_map["HAND"]->name = name;
293
-
}
294
-
}
295
-
296
// NOTE: No operations that would force inputs_vec or finger_inputs_vec to reallocate (such as insertion)
297
// should be done after this function is called, otherwise the pointers in inputs_map/finger_inputs_map
298
// would be invalidated.
···
314
inputs_map.insert({path, &inputs_vec.back()});
315
}
316
317
-
has_index_hand_tracking = debug_get_bool_option_lh_emulate_hand() && !input_class->finger_curls.empty();
318
-
if (has_index_hand_tracking) {
319
-
finger_inputs_vec.reserve(input_class->finger_curls.size());
320
-
for (const auto &[path, finger] : input_class->finger_curls) {
321
-
assert(finger_inputs_vec.capacity() >= finger_inputs_vec.size() + 1);
322
-
finger_inputs_vec.push_back({0, finger, 0.f});
323
-
finger_inputs_map.insert({path, &finger_inputs_vec.back()});
324
-
}
325
-
assert(inputs_vec.capacity() >= inputs_vec.size() + 1);
326
-
inputs_vec.push_back({true, 0, XRT_INPUT_HT_CONFORMING_LEFT, {}});
327
-
inputs_map.insert({std::string_view("HAND"), &inputs_vec.back()});
328
-
}
329
-
330
this->inputs = inputs_vec.data();
331
this->input_count = inputs_vec.size();
332
}
···
345
}
346
}
347
348
-
const std::vector<std::string> FACE_BUTTONS = {
349
-
"/input/system/touch", "/input/a/touch", "/input/b/touch", "/input/thumbstick/touch", "/input/trackpad/touch",
350
-
};
351
352
void
353
-
ControllerDevice::update_hand_tracking(int64_t desired_timestamp_ns, struct xrt_hand_joint_set *out)
354
{
355
-
if (!has_index_hand_tracking)
356
return;
357
-
float index = 0.f;
358
-
float middle = 0.f;
359
-
float ring = 0.f;
360
-
float pinky = 0.f;
361
-
float thumb = 0.f;
362
-
for (auto fi : finger_inputs_vec) {
363
-
switch (fi.finger) {
364
-
case IndexFinger::Index: index = fi.value; break;
365
-
case IndexFinger::Middle: middle = fi.value; break;
366
-
case IndexFinger::Ring: ring = fi.value; break;
367
-
case IndexFinger::Pinky: pinky = fi.value; break;
368
-
default: break;
369
-
}
370
}
371
-
for (const auto &name : FACE_BUTTONS) {
372
-
auto *input = get_input_from_name(name);
373
-
if (input && input->value.boolean) {
374
-
thumb = 1.f;
375
-
break;
376
-
}
377
}
378
-
auto curl_values = u_hand_tracking_curl_values{pinky, ring, middle, index, thumb};
379
380
-
struct xrt_space_relation hand_relation = {};
381
-
m_relation_history_get(relation_hist, desired_timestamp_ns, &hand_relation);
382
383
-
u_hand_sim_simulate_for_valve_index_knuckles(&curl_values, get_xrt_hand(), &hand_relation, out);
384
385
-
struct xrt_relation_chain chain = {};
386
387
-
struct xrt_pose pose_offset = XRT_POSE_IDENTITY;
388
-
vive_poses_get_pose_offset(name, device_type, inputs_map["HAND"]->name, &pose_offset);
389
390
-
m_relation_chain_push_pose(&chain, &pose_offset);
391
-
m_relation_chain_push_relation(&chain, &hand_relation);
392
-
m_relation_chain_resolve(&chain, &out->hand_pose);
393
}
394
395
xrt_input *
396
Device::get_input_from_name(const std::string_view name)
397
{
398
// Return nullptr without any other output to suppress a pile of useless warnings found below.
399
-
if (name == "/input/finger/index" || name == "/input/finger/middle" || name == "/input/finger/ring" ||
400
-
name == "/input/finger/pinky") {
401
return nullptr;
402
}
403
auto input = inputs_map.find(name);
···
447
return XRT_SUCCESS;
448
}
449
450
-
IndexFingerInput *
451
-
ControllerDevice::get_finger_from_name(const std::string_view name)
452
-
{
453
-
auto finger = finger_inputs_map.find(name);
454
-
if (finger == finger_inputs_map.end()) {
455
-
DEV_WARN("requested unknown finger name %s for device %s", std::string(name).c_str(), serial);
456
-
return nullptr;
457
-
}
458
-
return finger->second;
459
-
}
460
-
461
xrt_result_t
462
ControllerDevice::get_hand_tracking(enum xrt_input_name name,
463
int64_t desired_timestamp_ns,
464
struct xrt_hand_joint_set *out_value,
465
int64_t *out_timestamp_ns)
466
{
467
-
if (!has_index_hand_tracking)
468
return XRT_ERROR_NOT_IMPLEMENTED;
469
-
update_hand_tracking(desired_timestamp_ns, out_value);
470
-
out_value->is_active = true;
471
-
hand_tracking_timestamp = desired_timestamp_ns;
472
-
*out_timestamp_ns = hand_tracking_timestamp;
473
return XRT_SUCCESS;
474
}
475
···
527
Device::get_pose(at_timestamp_ns, &rel);
528
529
xrt_pose pose_offset = XRT_POSE_IDENTITY;
530
-
vive_poses_get_pose_offset(input_class->name, device_type, name, &pose_offset);
531
532
xrt_relation_chain relchain = {};
533
534
m_relation_chain_push_pose(&relchain, &pose_offset);
···
605
xrt_result_t
606
HmdDevice::get_view_poses(const xrt_vec3 *default_eye_relation,
607
uint64_t at_timestamp_ns,
608
uint32_t view_count,
609
xrt_space_relation *out_head_relation,
610
xrt_fov *out_fovs,
···
617
this, //
618
&eye_relation, //
619
at_timestamp_ns, //
620
view_count, //
621
out_head_relation, //
622
out_fovs, //
···
804
relation.linear_velocity = copy_vec3(newPose.vecVelocity);
805
relation.angular_velocity = copy_vec3(newPose.vecAngularVelocity);
806
807
math_quat_rotate_vec3(&relation.pose.orientation, &relation.angular_velocity, &relation.angular_velocity);
808
-
809
-
// apply over local transform
810
-
const xrt_pose local = copy_pose(newPose.qDriverFromHeadRotation, newPose.vecDriverFromHeadTranslation);
811
math_pose_transform(&relation.pose, &local, &relation.pose);
812
813
// apply world transform
···
868
}
869
870
void
871
-
HmdDevice::set_scanout_type(xrt_scanout_direction direction, uint64_t time_ns)
872
{
873
auto set = [this, direction, time_ns] {
874
hmd_parts->base.screens[0].scanout_direction = direction;
···
1047
case vr::Prop_DisplayFrequency_Float: {
1048
assert(prop.unBufferSize == sizeof(float));
1049
float freq = *static_cast<float *>(prop.pvBuffer);
1050
-
uint64_t interval_ns = (1.f / freq) * 1e9f;
1051
set_nominal_frame_interval(interval_ns);
1052
if (variant == VIVE_VARIANT_PRO) {
1053
set_scanout_type(XRT_SCANOUT_DIRECTION_TOP_TO_BOTTOM, interval_ns * 1600.0 / 1624.0);
···
1129
const std::string_view name = {static_cast<char *>(prop.pvBuffer), prop.unBufferSize};
1130
if (name == "SlimeVR Virtual Tracker\0"sv) {
1131
static const InputClass input_class = {
1132
-
XRT_DEVICE_VIVE_TRACKER, {XRT_INPUT_GENERIC_TRACKER_POSE}, {}, {}};
1133
this->name = input_class.name;
1134
set_input_class(&input_class);
1135
this->manufacturer = name.substr(0, name.find_first_of(' '));
···
1148
}
1149
case vr::TrackedControllerRole_RightHand: {
1150
this->device_type = XRT_DEVICE_TYPE_RIGHT_HAND_CONTROLLER;
1151
-
set_hand_tracking_hand(XRT_INPUT_HT_CONFORMING_RIGHT);
1152
break;
1153
}
1154
case vr::TrackedControllerRole_LeftHand: {
1155
this->device_type = XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER;
1156
-
set_hand_tracking_hand(XRT_INPUT_HT_CONFORMING_LEFT);
1157
break;
1158
}
1159
case vr::TrackedControllerRole_OptOut: {
···
9
*/
10
11
#include "math/m_api.h"
12
+
#include "math/m_predict.h"
13
#include "math/m_relation_history.h"
14
#include "math/m_space.h"
15
···
17
18
#include "util/u_debug.h"
19
#include "util/u_device.h"
20
#include "util/u_hand_tracking.h"
21
#include "util/u_logging.h"
22
#include "util/u_json.hpp"
23
24
+
#include "util/u_time.h"
25
#include "xrt/xrt_defines.h"
26
#include "xrt/xrt_device.h"
27
#include "xrt/xrt_prober.h"
···
35
#include <cmath>
36
#include <functional>
37
#include <cstring>
38
+
#include <numbers>
39
+
#include <openvr_driver.h>
40
#include <thread>
41
#include <algorithm>
42
#include <map>
43
44
#define DEV_ERR(...) U_LOG_IFL_E(ctx->log_level, __VA_ARGS__)
45
#define DEV_WARN(...) U_LOG_IFL_W(ctx->log_level, __VA_ARGS__)
···
54
xrt_device_name name;
55
const std::vector<xrt_input_name> poses;
56
const std::unordered_map<std::string_view, xrt_input_name> non_poses;
57
};
58
59
namespace {
60
+
using namespace std::string_view_literals;
61
+
// From https://github.com/ValveSoftware/openvr/blob/master/docs/Driver_API_Documentation.md#bone-structure
62
+
enum HandSkeletonBone : int32_t
63
+
{
64
+
eBone_Root = 0,
65
+
eBone_Wrist,
66
+
eBone_Thumb0,
67
+
eBone_Thumb1,
68
+
eBone_Thumb2,
69
+
eBone_Thumb3,
70
+
eBone_IndexFinger0,
71
+
eBone_IndexFinger1,
72
+
eBone_IndexFinger2,
73
+
eBone_IndexFinger3,
74
+
eBone_IndexFinger4,
75
+
eBone_MiddleFinger0,
76
+
eBone_MiddleFinger1,
77
+
eBone_MiddleFinger2,
78
+
eBone_MiddleFinger3,
79
+
eBone_MiddleFinger4,
80
+
eBone_RingFinger0,
81
+
eBone_RingFinger1,
82
+
eBone_RingFinger2,
83
+
eBone_RingFinger3,
84
+
eBone_RingFinger4,
85
+
eBone_PinkyFinger0,
86
+
eBone_PinkyFinger1,
87
+
eBone_PinkyFinger2,
88
+
eBone_PinkyFinger3,
89
+
eBone_PinkyFinger4,
90
+
eBone_Aux_Thumb,
91
+
eBone_Aux_IndexFinger,
92
+
eBone_Aux_MiddleFinger,
93
+
eBone_Aux_RingFinger,
94
+
eBone_Aux_PinkyFinger,
95
+
eBone_Count
96
+
};
97
+
98
// Adding support for a new controller is a simple as adding it here.
99
// The key for the map needs to be the name of input profile as indicated by the lighthouse driver.
100
const std::unordered_map<std::string_view, InputClass> controller_classes{
···
105
{
106
XRT_INPUT_VIVE_GRIP_POSE,
107
XRT_INPUT_VIVE_AIM_POSE,
108
+
XRT_INPUT_GENERIC_PALM_POSE,
109
},
110
{
111
{"/input/application_menu/click", XRT_INPUT_VIVE_MENU_CLICK},
···
116
{"/input/trigger/value", XRT_INPUT_VIVE_TRIGGER_VALUE},
117
{"/input/grip/click", XRT_INPUT_VIVE_SQUEEZE_CLICK},
118
{"/input/trackpad", XRT_INPUT_VIVE_TRACKPAD},
119
},
120
},
121
},
···
126
{
127
XRT_INPUT_INDEX_GRIP_POSE,
128
XRT_INPUT_INDEX_AIM_POSE,
129
+
XRT_INPUT_GENERIC_PALM_POSE,
130
},
131
{
132
{"/input/system/click", XRT_INPUT_INDEX_SYSTEM_CLICK},
···
147
{"/input/trackpad/touch", XRT_INPUT_INDEX_TRACKPAD_TOUCH},
148
{"/input/trackpad", XRT_INPUT_INDEX_TRACKPAD},
149
},
150
},
151
},
152
{
···
162
{"/input/application_menu/click", XRT_INPUT_VIVE_TRACKER_MENU_CLICK},
163
{"/input/trigger/click", XRT_INPUT_VIVE_TRACKER_TRIGGER_CLICK},
164
{"/input/thumb/click", XRT_INPUT_VIVE_TRACKER_TRACKPAD_CLICK},
165
},
166
},
167
},
···
179
{"/input/trigger/click", XRT_INPUT_VIVE_TRACKER_TRIGGER_CLICK},
180
{"/input/thumb/click", XRT_INPUT_VIVE_TRACKER_TRACKPAD_CLICK},
181
},
182
},
183
},
184
};
185
int64_t
186
chrono_timestamp_ns()
187
{
···
239
240
return brightness;
241
}
242
+
xrt_pose
243
+
bone_to_pose(const vr::VRBoneTransform_t &bone)
244
+
{
245
+
return xrt_pose{xrt_quat{bone.orientation.x, bone.orientation.y, bone.orientation.z, bone.orientation.w},
246
+
xrt_vec3{bone.position.v[0], bone.position.v[1], bone.position.v[2]}};
247
+
}
248
} // namespace
249
250
Property::Property(vr::PropertyTypeTag_t tag, void *buffer, uint32_t bufferSize)
···
280
this->xrt_device::get_hand_tracking =
281
&device_bouncer<ControllerDevice, &ControllerDevice::get_hand_tracking, xrt_result_t>;
282
this->xrt_device::set_output = &device_bouncer<ControllerDevice, &ControllerDevice::set_output, xrt_result_t>;
283
+
284
+
this->inputs_map["/skeleton/hand/left"] = &hand_tracking_inputs[XRT_HAND_LEFT];
285
+
this->inputs_map["/skeleton/hand/right"] = &hand_tracking_inputs[XRT_HAND_RIGHT];
286
}
287
288
Device::~Device()
···
319
init_chaperone(builder.steam_install);
320
}
321
322
// NOTE: No operations that would force inputs_vec or finger_inputs_vec to reallocate (such as insertion)
323
// should be done after this function is called, otherwise the pointers in inputs_map/finger_inputs_map
324
// would be invalidated.
···
340
inputs_map.insert({path, &inputs_vec.back()});
341
}
342
343
this->inputs = inputs_vec.data();
344
this->input_count = inputs_vec.size();
345
}
···
358
}
359
}
360
361
+
void
362
+
ControllerDevice::set_active_hand(xrt_hand hand)
363
+
{
364
+
this->skeleton_hand = hand;
365
+
}
366
+
367
+
namespace {
368
+
xrt_quat
369
+
from_euler_angles(float x, float y, float z)
370
+
{
371
+
const xrt_vec3 v{x, y, z};
372
+
xrt_quat out;
373
+
math_quat_from_euler_angles(&v, &out);
374
+
return out;
375
+
}
376
+
377
+
constexpr float pi = std::numbers::pi_v<float>;
378
+
constexpr float frac_pi_2 = pi / 2.0f;
379
+
380
+
// OpenVR skeletal poses are defined with the palms facing each other, but OpenXR
381
+
// hand tracking is defined with the palms facing down. These per hand rotations
382
+
// are necessary to translate to what OpenXR expects.
383
+
const xrt_quat right_hand_rotate = from_euler_angles(0.0f, frac_pi_2, 0.0f);
384
+
const xrt_quat left_hand_rotate = from_euler_angles(0.0f, frac_pi_2, pi);
385
+
386
+
xrt_quat
387
+
right_wrist_rotate_init()
388
+
{
389
+
const xrt_quat rot1 = from_euler_angles(0.0f, 0.0f, frac_pi_2);
390
+
const xrt_quat rot2 = from_euler_angles(0.0f, pi, 0.0f);
391
+
xrt_quat ret;
392
+
math_quat_rotate(&rot1, &rot2, &ret);
393
+
return ret;
394
+
}
395
+
xrt_quat
396
+
left_wrist_rotate_init()
397
+
{
398
+
const xrt_quat rot1 = from_euler_angles(pi, 0.0f, 0.0f);
399
+
const xrt_quat rot2 = from_euler_angles(0.0f, 0.0f, -frac_pi_2);
400
+
xrt_quat ret;
401
+
math_quat_rotate(&rot1, &rot2, &ret);
402
+
return ret;
403
+
}
404
+
405
+
const xrt_quat right_wrist_rotate = right_wrist_rotate_init();
406
+
const xrt_quat left_wrist_rotate = left_wrist_rotate_init();
407
+
408
+
xrt_pose
409
+
generate_palm_pose(const xrt_pose &metacarpal_pose, const xrt_pose &proximal_pose)
410
+
{
411
+
// OpenVR doesn't provide a palm joint, but the OpenXR palm is in the middle of
412
+
// the metacarpal and proximal bones of the middle finger,
413
+
// so we'll interpolate between them to generate it.
414
+
xrt_pose pose;
415
+
math_pose_interpolate(&metacarpal_pose, &proximal_pose, 0.5, &pose);
416
+
// Use metacarpal orientation, because the palm shouldn't really rotate
417
+
pose.orientation = metacarpal_pose.orientation;
418
+
return pose;
419
+
}
420
+
421
+
xrt_pose
422
+
palm_offset_index(xrt_hand hand)
423
+
{
424
+
// Taken from:
425
+
// https://github.com/ValveSoftware/OpenXR-Canonical-Pose-Tool/blob/5e6f3f6db584d58483058ff3262e7eef02c3acfd/dist/steamvr/cpt_SteamVR-valve_index_controller.xml#L1
426
+
switch (hand) {
427
+
case XRT_HAND_LEFT:
428
+
return xrt_pose{.orientation = xrt_quat{.x = -0.46, .y = -0.02, .z = -0.01, .w = 0.89},
429
+
.position = xrt_vec3{.x = -0.015, .y = 0.0, .z = 0.001}};
430
+
case XRT_HAND_RIGHT:
431
+
return xrt_pose{.orientation = xrt_quat{.x = -0.46, .y = 0.02, .z = 0.01, .w = 0.89},
432
+
.position = xrt_vec3{.x = 0.015, .y = 0.0, .z = 0.001}};
433
+
}
434
+
435
+
return {};
436
+
}
437
+
438
+
} // namespace
439
440
void
441
+
ControllerDevice::set_skeleton(std::span<const vr::VRBoneTransform_t> bones,
442
+
xrt_hand hand,
443
+
bool is_simulated,
444
+
const char *path)
445
{
446
+
assert(bones.size() == eBone_Count);
447
+
generate_palm_pose_offset(bones, hand);
448
+
if (!is_simulated && debug_get_bool_option_lh_emulate_hand()) {
449
+
assert(inputs_vec.capacity() >= inputs_vec.size() + 1);
450
+
const xrt_input_name tracker_name =
451
+
(hand == XRT_HAND_RIGHT) ? XRT_INPUT_HT_CONFORMING_RIGHT : XRT_INPUT_HT_CONFORMING_LEFT;
452
+
inputs_vec.push_back({true, 0, tracker_name, {}});
453
+
inputs_map.insert({path, &inputs_vec.back()});
454
+
this->input_count = inputs_vec.size();
455
+
has_hand_tracking = true;
456
+
}
457
+
}
458
+
459
+
void
460
+
ControllerDevice::generate_palm_pose_offset(std::span<const vr::VRBoneTransform_t> bones, xrt_hand hand)
461
+
{
462
+
if (this->input_class->name == XRT_DEVICE_INDEX_CONTROLLER) {
463
+
xrt_pose grip_offset;
464
+
vive_poses_get_pose_offset(this->input_class->name, this->device_type, XRT_INPUT_INDEX_GRIP_POSE,
465
+
&grip_offset);
466
+
auto offset = palm_offset_index(hand);
467
+
math_pose_transform(&grip_offset, &offset, &offset);
468
+
palm_offsets[hand] = offset;
469
return;
470
}
471
+
// The palm pose offset is generated from the OpenVR provided skeleton.
472
+
// https://github.com/ValveSoftware/openvr/blob/master/docs/Driver_API_Documentation.md#notes-on-the-skeleton
473
+
474
+
xrt_pose root = bone_to_pose(bones[eBone_Root]);
475
+
xrt_pose wrist = bone_to_pose(bones[eBone_Wrist]);
476
+
xrt_pose metacarpal = bone_to_pose(bones[eBone_MiddleFinger0]);
477
+
xrt_pose proximal = bone_to_pose(bones[eBone_MiddleFinger1]);
478
+
479
+
// The skeleton pose is given with the Root bone as origin.
480
+
// To convert from this, according to OpenVR docs we transform the wrist
481
+
// and then counter-transform the metacarpals
482
+
xrt_pose root_inv;
483
+
math_pose_invert(&root, &root_inv);
484
+
math_pose_transform(&root_inv, &wrist, &wrist);
485
+
math_pose_transform(&root, &metacarpal, &metacarpal);
486
+
math_pose_transform(&wrist, &metacarpal, &metacarpal);
487
+
math_pose_transform(&metacarpal, &proximal, &proximal);
488
+
489
+
xrt_pose palm_offset = generate_palm_pose(metacarpal, proximal);
490
+
xrt_quat palm_rotate = from_euler_angles(0.0f, 0.0f, frac_pi_2);
491
+
492
+
switch (hand) {
493
+
case XRT_HAND_LEFT: {
494
+
math_quat_rotate(&palm_offset.orientation, &left_hand_rotate, &palm_offset.orientation);
495
+
math_quat_invert(&palm_rotate, &palm_rotate);
496
+
break;
497
}
498
+
case XRT_HAND_RIGHT: {
499
+
math_quat_rotate(&palm_offset.orientation, &right_hand_rotate, &palm_offset.orientation);
500
+
break;
501
+
}
502
+
}
503
+
math_quat_rotate(&palm_offset.orientation, &palm_rotate, &palm_offset.orientation);
504
+
505
+
// For controllers like the Vive Wands which can be in any hand, it will store both the left hand
506
+
// and the right hand skeletons, so we need to store both.
507
+
palm_offsets[hand] = palm_offset;
508
+
}
509
+
510
+
void
511
+
ControllerDevice::update_skeleton_transforms(std::span<const vr::VRBoneTransform_t> bones)
512
+
{
513
+
if (!has_hand_tracking) {
514
+
return;
515
+
}
516
+
517
+
assert(bones.size() == eBone_Count);
518
+
519
+
xrt_hand_joint_set joint_set;
520
+
int64_t timestamp;
521
+
if (!m_relation_history_get_latest(relation_hist, ×tamp, &joint_set.hand_pose)) {
522
+
return;
523
+
}
524
+
joint_set.is_active = true;
525
+
auto &joints = joint_set.values.hand_joint_set_default;
526
+
527
+
xrt_pose root = bone_to_pose(bones[eBone_Root]);
528
+
xrt_pose wrist = bone_to_pose(bones[eBone_Wrist]);
529
+
530
+
// Here we're doing the same transformation as seen in generate_palm_pose_offset.
531
+
xrt_pose root_inv;
532
+
math_pose_invert(&root, &root_inv);
533
+
math_pose_transform(&root_inv, &wrist, &wrist);
534
+
535
+
constexpr auto valid_flags = (enum xrt_space_relation_flags)(
536
+
XRT_SPACE_RELATION_POSITION_VALID_BIT | XRT_SPACE_RELATION_ORIENTATION_VALID_BIT |
537
+
XRT_SPACE_RELATION_POSITION_TRACKED_BIT | XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT);
538
+
539
+
xrt_pose wrist_xr = wrist;
540
+
541
+
switch (skeleton_hand) {
542
+
case XRT_HAND_LEFT: {
543
+
math_quat_rotate(&wrist_xr.orientation, &left_wrist_rotate, &wrist_xr.orientation);
544
+
break;
545
+
}
546
+
case XRT_HAND_RIGHT: {
547
+
math_quat_rotate(&wrist_xr.orientation, &right_wrist_rotate, &wrist_xr.orientation);
548
+
break;
549
+
}
550
+
}
551
552
+
joints[XRT_HAND_JOINT_WRIST].relation.pose = wrist_xr;
553
+
joints[XRT_HAND_JOINT_WRIST].relation.relation_flags = valid_flags;
554
555
+
xrt_pose parent_pose;
556
+
for (int joint = XRT_HAND_JOINT_THUMB_METACARPAL; joint <= XRT_HAND_JOINT_LITTLE_TIP; ++joint) {
557
+
// Luckily openvr and openxr joint values match
558
+
xrt_pose pose = bone_to_pose(bones[joint]);
559
+
joints[joint].relation.relation_flags = valid_flags;
560
561
+
if (u_hand_joint_is_metacarpal((xrt_hand_joint)joint)) {
562
+
// Counter transform metacarpals
563
+
math_pose_transform(&root, &pose, &pose);
564
+
math_pose_transform(&wrist, &pose, &pose);
565
+
} else {
566
+
math_pose_transform(&parent_pose, &pose, &pose);
567
+
}
568
569
+
parent_pose = pose;
570
+
571
+
// Rotate joint to OpenXR orientation
572
+
switch (skeleton_hand) {
573
+
case XRT_HAND_LEFT: math_quat_rotate(&pose.orientation, &left_hand_rotate, &pose.orientation); break;
574
+
case XRT_HAND_RIGHT: math_quat_rotate(&pose.orientation, &right_hand_rotate, &pose.orientation); break;
575
+
}
576
+
joints[joint].relation.pose = pose;
577
+
}
578
+
579
+
joints[XRT_HAND_JOINT_PALM].relation.relation_flags = valid_flags;
580
+
joints[XRT_HAND_JOINT_PALM].relation.pose =
581
+
generate_palm_pose(joints[XRT_HAND_JOINT_MIDDLE_METACARPAL].relation.pose,
582
+
joints[XRT_HAND_JOINT_MIDDLE_PROXIMAL].relation.pose);
583
584
+
u_hand_joints_apply_joint_width(&joint_set);
585
+
this->joint_history.push_back(JointsWithTimestamp{joint_set, timestamp});
586
}
587
588
xrt_input *
589
Device::get_input_from_name(const std::string_view name)
590
{
591
+
static const std::array ignore_inputs = {"/input/finger/index"sv, "/input/finger/middle"sv,
592
+
"/input/finger/ring"sv, "/input/finger/pinky"sv,
593
+
"/input/grip/touch"sv};
594
+
595
// Return nullptr without any other output to suppress a pile of useless warnings found below.
596
+
if (std::ranges::find(ignore_inputs, name) != std::ranges::end(ignore_inputs)) {
597
return nullptr;
598
}
599
auto input = inputs_map.find(name);
···
643
return XRT_SUCCESS;
644
}
645
646
xrt_result_t
647
ControllerDevice::get_hand_tracking(enum xrt_input_name name,
648
int64_t desired_timestamp_ns,
649
struct xrt_hand_joint_set *out_value,
650
int64_t *out_timestamp_ns)
651
{
652
+
if (!has_hand_tracking) {
653
return XRT_ERROR_NOT_IMPLEMENTED;
654
+
}
655
+
656
+
// No handtracking data?
657
+
if (joint_history.empty()) {
658
+
out_value->is_active = false;
659
+
return XRT_SUCCESS;
660
+
}
661
+
662
+
const auto it = std::ranges::lower_bound(joint_history, desired_timestamp_ns, {},
663
+
[](const JointsWithTimestamp &joint) { return joint.timestamp; });
664
+
665
+
auto predict_joint_set = [out_value, out_timestamp_ns,
666
+
desired_timestamp_ns](const JointsWithTimestamp &joints) {
667
+
out_value->is_active = joints.joint_set.is_active;
668
+
int64_t delta_ns = desired_timestamp_ns - joints.timestamp;
669
+
double delta_s = time_ns_to_s(delta_ns);
670
+
671
+
*out_timestamp_ns = desired_timestamp_ns;
672
+
m_predict_relation(&joints.joint_set.hand_pose, delta_s, &out_value->hand_pose);
673
+
for (int i = 0; i < XRT_HAND_JOINT_COUNT; i++) {
674
+
auto &new_joint = joints.joint_set.values.hand_joint_set_default[i];
675
+
auto &interp_joint = out_value->values.hand_joint_set_default[i];
676
+
677
+
m_predict_relation(&new_joint.relation, delta_s, &interp_joint.relation);
678
+
interp_joint.radius = new_joint.radius;
679
+
}
680
+
};
681
+
682
+
if (it == joint_history.end()) {
683
+
// Timestamp is newer than anything in history
684
+
predict_joint_set(joint_history.back());
685
+
} else if (desired_timestamp_ns == it->timestamp) {
686
+
*out_value = it->joint_set;
687
+
*out_timestamp_ns = it->timestamp;
688
+
} else if (it == joint_history.begin()) {
689
+
// Timestamp is older than anything in history
690
+
predict_joint_set(joint_history.front());
691
+
} else {
692
+
// Interpolate
693
+
auto it_previous = it - 1;
694
+
695
+
auto delta_before = desired_timestamp_ns - it_previous->timestamp;
696
+
auto delta_after = it->timestamp - desired_timestamp_ns;
697
+
float lerp_amt = (float)delta_before / (float)(delta_after - delta_before);
698
+
699
+
auto interpolate = [lerp_amt](xrt_space_relation &previous, xrt_space_relation &next,
700
+
xrt_space_relation &out) {
701
+
auto flags = (xrt_space_relation_flags)(previous.relation_flags & next.relation_flags);
702
+
m_space_relation_interpolate(&previous, &next, lerp_amt, flags, &out);
703
+
};
704
+
705
+
interpolate(it_previous->joint_set.hand_pose, it->joint_set.hand_pose, out_value->hand_pose);
706
+
707
+
for (int i = 0; i < XRT_HAND_JOINT_COUNT; i++) {
708
+
auto &prev = it_previous->joint_set.values.hand_joint_set_default[i];
709
+
auto &next = it->joint_set.values.hand_joint_set_default[i];
710
+
auto &out = out_value->values.hand_joint_set_default[i];
711
+
interpolate(prev.relation, next.relation, out.relation);
712
+
out.radius = next.radius;
713
+
}
714
+
715
+
*out_timestamp_ns = desired_timestamp_ns;
716
+
}
717
+
718
return XRT_SUCCESS;
719
}
720
···
772
Device::get_pose(at_timestamp_ns, &rel);
773
774
xrt_pose pose_offset = XRT_POSE_IDENTITY;
775
776
+
if (name == XRT_INPUT_GENERIC_PALM_POSE) {
777
+
if (!palm_offsets[skeleton_hand].has_value()) {
778
+
DEV_ERR("%s hand skeleton has not been initialized",
779
+
skeleton_hand == XRT_HAND_LEFT ? "left" : "right");
780
+
*out_relation = XRT_SPACE_RELATION_ZERO;
781
+
return XRT_SUCCESS;
782
+
}
783
+
pose_offset = *palm_offsets[skeleton_hand];
784
+
} else {
785
+
vive_poses_get_pose_offset(input_class->name, device_type, name, &pose_offset);
786
+
}
787
xrt_relation_chain relchain = {};
788
789
m_relation_chain_push_pose(&relchain, &pose_offset);
···
860
xrt_result_t
861
HmdDevice::get_view_poses(const xrt_vec3 *default_eye_relation,
862
uint64_t at_timestamp_ns,
863
+
xrt_view_type view_type,
864
uint32_t view_count,
865
xrt_space_relation *out_head_relation,
866
xrt_fov *out_fovs,
···
873
this, //
874
&eye_relation, //
875
at_timestamp_ns, //
876
+
view_type, //
877
view_count, //
878
out_head_relation, //
879
out_fovs, //
···
1061
relation.linear_velocity = copy_vec3(newPose.vecVelocity);
1062
relation.angular_velocity = copy_vec3(newPose.vecAngularVelocity);
1063
1064
+
// local transform (head to driver offset)
1065
+
const xrt_pose local = copy_pose(newPose.qDriverFromHeadRotation, newPose.vecDriverFromHeadTranslation);
1066
+
1067
+
// IMU linear velocity contribution due to rotation around driver origin (tangential velocity)
1068
+
xrt_vec3 tangential_velocity;
1069
+
math_vec3_cross(&relation.angular_velocity, &local.position, &tangential_velocity);
1070
+
math_quat_rotate_vec3(&relation.pose.orientation, &tangential_velocity, &tangential_velocity);
1071
+
math_vec3_accum(&tangential_velocity, &relation.linear_velocity);
1072
+
1073
+
// apply local transform
1074
math_quat_rotate_vec3(&relation.pose.orientation, &relation.angular_velocity, &relation.angular_velocity);
1075
math_pose_transform(&relation.pose, &local, &relation.pose);
1076
1077
// apply world transform
···
1132
}
1133
1134
void
1135
+
HmdDevice::set_scanout_type(xrt_scanout_direction direction, int64_t time_ns)
1136
{
1137
auto set = [this, direction, time_ns] {
1138
hmd_parts->base.screens[0].scanout_direction = direction;
···
1311
case vr::Prop_DisplayFrequency_Float: {
1312
assert(prop.unBufferSize == sizeof(float));
1313
float freq = *static_cast<float *>(prop.pvBuffer);
1314
+
int64_t interval_ns = (1.f / freq) * 1e9f;
1315
set_nominal_frame_interval(interval_ns);
1316
if (variant == VIVE_VARIANT_PRO) {
1317
set_scanout_type(XRT_SCANOUT_DIRECTION_TOP_TO_BOTTOM, interval_ns * 1600.0 / 1624.0);
···
1393
const std::string_view name = {static_cast<char *>(prop.pvBuffer), prop.unBufferSize};
1394
if (name == "SlimeVR Virtual Tracker\0"sv) {
1395
static const InputClass input_class = {
1396
+
XRT_DEVICE_VIVE_TRACKER, {XRT_INPUT_GENERIC_TRACKER_POSE}, {}};
1397
this->name = input_class.name;
1398
set_input_class(&input_class);
1399
this->manufacturer = name.substr(0, name.find_first_of(' '));
···
1412
}
1413
case vr::TrackedControllerRole_RightHand: {
1414
this->device_type = XRT_DEVICE_TYPE_RIGHT_HAND_CONTROLLER;
1415
+
set_active_hand(XRT_HAND_RIGHT);
1416
break;
1417
}
1418
case vr::TrackedControllerRole_LeftHand: {
1419
this->device_type = XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER;
1420
+
set_active_hand(XRT_HAND_LEFT);
1421
break;
1422
}
1423
case vr::TrackedControllerRole_OptOut: {
+26
-11
src/xrt/drivers/steamvr_lh/device.hpp
+26
-11
src/xrt/drivers/steamvr_lh/device.hpp
···
11
12
#include "math/m_relation_history.h"
13
14
#include "xrt/xrt_device.h"
15
16
#include "vive/vive_common.h"
···
23
#include <vector>
24
#include <memory>
25
#include <unordered_map>
26
27
#include <condition_variable>
28
#include <mutex>
···
176
xrt_result_t
177
get_view_poses(const xrt_vec3 *default_eye_relation,
178
uint64_t at_timestamp_ns,
179
uint32_t view_count,
180
xrt_space_relation *out_head_relation,
181
xrt_fov *out_fovs,
···
211
set_nominal_frame_interval(uint64_t interval_ns);
212
213
void
214
-
set_scanout_type(enum xrt_scanout_direction direction, uint64_t time_ns);
215
216
std::condition_variable hmd_parts_cv;
217
std::mutex hmd_parts_mut;
···
233
xrt_result_t
234
get_tracked_pose(xrt_input_name name, uint64_t at_timestamp_ns, xrt_space_relation *out_relation) override;
235
236
-
IndexFingerInput *
237
-
get_finger_from_name(std::string_view name);
238
-
239
xrt_result_t
240
get_hand_tracking(enum xrt_input_name name,
241
int64_t desired_timestamp_ns,
···
246
get_xrt_hand();
247
248
void
249
-
update_hand_tracking(int64_t desired_timestamp_ns, struct xrt_hand_joint_set *out);
250
251
protected:
252
void
253
set_input_class(const InputClass *input_class);
254
255
private:
256
vr::VRInputComponentHandle_t haptic_handle{0};
257
std::unique_ptr<xrt_output> output{nullptr};
258
-
bool has_index_hand_tracking{false};
259
-
std::vector<IndexFingerInput> finger_inputs_vec;
260
-
std::unordered_map<std::string_view, IndexFingerInput *> finger_inputs_map;
261
-
uint64_t hand_tracking_timestamp;
262
263
-
void
264
-
set_hand_tracking_hand(xrt_input_name name);
265
266
vr::ETrackedPropertyError
267
handle_property_write(const vr::PropertyWrite_t &prop) override;
···
11
12
#include "math/m_relation_history.h"
13
14
+
#include "util/u_template_historybuf.hpp"
15
#include "xrt/xrt_device.h"
16
17
#include "vive/vive_common.h"
···
24
#include <vector>
25
#include <memory>
26
#include <unordered_map>
27
+
#include <span>
28
+
#include <array>
29
+
#include <optional>
30
31
#include <condition_variable>
32
#include <mutex>
···
180
xrt_result_t
181
get_view_poses(const xrt_vec3 *default_eye_relation,
182
uint64_t at_timestamp_ns,
183
+
xrt_view_type view_type,
184
uint32_t view_count,
185
xrt_space_relation *out_head_relation,
186
xrt_fov *out_fovs,
···
216
set_nominal_frame_interval(uint64_t interval_ns);
217
218
void
219
+
set_scanout_type(enum xrt_scanout_direction direction, int64_t time_ns);
220
221
std::condition_variable hmd_parts_cv;
222
std::mutex hmd_parts_mut;
···
238
xrt_result_t
239
get_tracked_pose(xrt_input_name name, uint64_t at_timestamp_ns, xrt_space_relation *out_relation) override;
240
241
xrt_result_t
242
get_hand_tracking(enum xrt_input_name name,
243
int64_t desired_timestamp_ns,
···
248
get_xrt_hand();
249
250
void
251
+
update_skeleton_transforms(std::span<const vr::VRBoneTransform_t> bones);
252
+
253
+
void
254
+
set_skeleton(std::span<const vr::VRBoneTransform_t> bones, xrt_hand hand, bool is_simulated, const char *path);
255
+
256
+
void
257
+
set_active_hand(xrt_hand hand);
258
259
protected:
260
void
261
set_input_class(const InputClass *input_class);
262
+
263
+
void
264
+
generate_palm_pose_offset(std::span<const vr::VRBoneTransform_t> bones, xrt_hand hand);
265
266
private:
267
vr::VRInputComponentHandle_t haptic_handle{0};
268
std::unique_ptr<xrt_output> output{nullptr};
269
+
bool has_hand_tracking{false};
270
+
xrt_hand skeleton_hand = XRT_HAND_LEFT;
271
+
std::array<std::optional<xrt_pose>, 2> palm_offsets;
272
+
std::array<xrt_input, 2> hand_tracking_inputs{};
273
274
+
struct JointsWithTimestamp
275
+
{
276
+
xrt_hand_joint_set joint_set;
277
+
int64_t timestamp{0};
278
+
};
279
+
xrt::auxiliary::util::HistoryBuffer<JointsWithTimestamp, 5> joint_history;
280
281
vr::ETrackedPropertyError
282
handle_property_write(const vr::PropertyWrite_t &prop) override;
+2
-17
src/xrt/drivers/steamvr_lh/interfaces/context.hpp
+2
-17
src/xrt/drivers/steamvr_lh/interfaces/context.hpp
···
28
29
#include "xrt/xrt_tracking.h"
30
31
-
enum IndexFinger
32
-
{
33
-
Invalid = -1,
34
-
Index = 1,
35
-
Middle,
36
-
Ring,
37
-
Pinky,
38
-
};
39
-
40
-
struct IndexFingerInput
41
-
{
42
-
int64_t timestamp;
43
-
IndexFinger finger;
44
-
float value;
45
-
};
46
-
47
struct xrt_input;
48
class Device;
49
class Context final : public xrt_tracking_origin,
50
public vr::IVRDriverContext,
51
public vr::IVRServerDriverHost,
···
70
71
std::vector<vr::VRInputComponentHandle_t> handles;
72
std::unordered_map<vr::VRInputComponentHandle_t, xrt_input *> handle_to_input;
73
-
std::unordered_map<vr::VRInputComponentHandle_t, IndexFingerInput *> handle_to_finger;
74
struct Vec2Components
75
{
76
vr::VRInputComponentHandle_t x;
···
78
};
79
std::unordered_map<vr::VRInputComponentHandle_t, Vec2Components *> vec2_inputs;
80
std::unordered_map<xrt_input *, std::unique_ptr<Vec2Components>> vec2_input_to_components;
81
82
struct Event
83
{
···
28
29
#include "xrt/xrt_tracking.h"
30
31
struct xrt_input;
32
class Device;
33
+
class ControllerDevice;
34
class Context final : public xrt_tracking_origin,
35
public vr::IVRDriverContext,
36
public vr::IVRServerDriverHost,
···
55
56
std::vector<vr::VRInputComponentHandle_t> handles;
57
std::unordered_map<vr::VRInputComponentHandle_t, xrt_input *> handle_to_input;
58
struct Vec2Components
59
{
60
vr::VRInputComponentHandle_t x;
···
62
};
63
std::unordered_map<vr::VRInputComponentHandle_t, Vec2Components *> vec2_inputs;
64
std::unordered_map<xrt_input *, std::unique_ptr<Vec2Components>> vec2_input_to_components;
65
+
std::unordered_map<vr::VRInputComponentHandle_t, ControllerDevice *> skeleton_to_controller;
66
67
struct Event
68
{
+57
-24
src/xrt/drivers/steamvr_lh/steamvr_lh.cpp
+57
-24
src/xrt/drivers/steamvr_lh/steamvr_lh.cpp
···
162
MATCH_INTERFACE(vr::IVRDriverManager_Version, &man);
163
MATCH_INTERFACE(vr::IVRBlockQueue_Version, &blockqueue);
164
MATCH_INTERFACE(vr::IVRPaths_Version, &paths);
165
166
// Internal interfaces
167
MATCH_INTERFACE("IVRServer_XXX", &server);
···
479
return vr::VRInputError_InvalidHandle;
480
}
481
if (xrt_input *input = device->get_input_from_name(name); input) {
482
-
CTX_DEBUG("creating component %s", name);
483
vr::VRInputComponentHandle_t handle = new_handle();
484
handle_to_input[handle] = input;
485
*pHandle = handle;
486
-
} else if (device != hmd) {
487
-
auto *controller = static_cast<ControllerDevice *>(device);
488
-
if (IndexFingerInput *finger = controller->get_finger_from_name(name); finger) {
489
-
CTX_DEBUG("creating finger component %s", name);
490
-
vr::VRInputComponentHandle_t handle = new_handle();
491
-
handle_to_finger[handle] = finger;
492
-
*pHandle = handle;
493
-
}
494
}
495
return vr::VRInputError_None;
496
}
···
593
} else {
594
input->value.vec1.x = fNewValue;
595
}
596
-
} else {
597
-
if (ulComponent != vr::k_ulInvalidInputComponentHandle) {
598
-
if (auto finger_input = handle_to_finger.find(ulComponent);
599
-
finger_input != handle_to_finger.end() && finger_input->second) {
600
-
auto now = std::chrono::steady_clock::now();
601
-
std::chrono::duration<double, std::chrono::seconds::period> offset_dur(fTimeOffset);
602
-
std::chrono::duration offset = (now + offset_dur).time_since_epoch();
603
-
int64_t timestamp =
604
-
std::chrono::duration_cast<std::chrono::nanoseconds>(offset).count();
605
-
finger_input->second->timestamp = timestamp;
606
-
finger_input->second->value = fNewValue;
607
-
} else {
608
-
CTX_WARN("Unmapped component %" PRIu64, ulComponent);
609
-
}
610
-
}
611
}
612
return vr::VRInputError_None;
613
}
···
649
uint32_t unGripLimitTransformCount,
650
vr::VRInputComponentHandle_t *pHandle)
651
{
652
return vr::VRInputError_None;
653
}
654
···
658
const vr::VRBoneTransform_t *pTransforms,
659
uint32_t unTransformCount)
660
{
661
return vr::VRInputError_None;
662
}
663
···
754
out_roles->left = left;
755
out_roles->right = right;
756
out_roles->gamepad = gamepad;
757
}
758
759
return XRT_SUCCESS;
···
162
MATCH_INTERFACE(vr::IVRDriverManager_Version, &man);
163
MATCH_INTERFACE(vr::IVRBlockQueue_Version, &blockqueue);
164
MATCH_INTERFACE(vr::IVRPaths_Version, &paths);
165
+
// This version of the interface is not in a public header.
166
+
// Luckily it seems to be compatible with the previous version.
167
+
MATCH_INTERFACE("IVRPaths_002", &paths);
168
169
// Internal interfaces
170
MATCH_INTERFACE("IVRServer_XXX", &server);
···
482
return vr::VRInputError_InvalidHandle;
483
}
484
if (xrt_input *input = device->get_input_from_name(name); input) {
485
+
CTX_DEBUG("creating component %s for %p", name, (void *)device);
486
vr::VRInputComponentHandle_t handle = new_handle();
487
handle_to_input[handle] = input;
488
*pHandle = handle;
489
}
490
return vr::VRInputError_None;
491
}
···
588
} else {
589
input->value.vec1.x = fNewValue;
590
}
591
}
592
return vr::VRInputError_None;
593
}
···
629
uint32_t unGripLimitTransformCount,
630
vr::VRInputComponentHandle_t *pHandle)
631
{
632
+
std::string_view path(pchSkeletonPath); // should be /skeleton/hand/left or /skeleton/hand/right
633
+
std::string_view skeleton_pfx("/skeleton/hand/");
634
+
if (!path.starts_with(skeleton_pfx)) {
635
+
CTX_ERR("Got invalid skeleton path: %s", std::string(path).c_str());
636
+
return vr::VRInputError_InvalidSkeleton;
637
+
}
638
+
639
+
if (auto ret = create_component_common(ulContainer, pchSkeletonPath, pHandle); ret != vr::VRInputError_None) {
640
+
return ret;
641
+
}
642
+
643
+
auto *device = static_cast<ControllerDevice *>(prop_container_to_device(ulContainer));
644
+
path.remove_prefix(skeleton_pfx.size());
645
+
xrt_hand hand;
646
+
if (path == "left") {
647
+
hand = XRT_HAND_LEFT;
648
+
} else if (path == "right") {
649
+
hand = XRT_HAND_RIGHT;
650
+
} else {
651
+
CTX_ERR("Got invalid skeleton path suffix: %s", std::string(path).c_str());
652
+
return vr::VRInputError_InvalidSkeleton;
653
+
}
654
+
655
+
device->set_skeleton(std::span(pGripLimitTransforms, unGripLimitTransformCount), hand,
656
+
eSkeletalTrackingLevel == vr::VRSkeletalTracking_Estimated, pchSkeletonPath);
657
+
skeleton_to_controller[*pHandle] = device;
658
+
659
return vr::VRInputError_None;
660
}
661
···
665
const vr::VRBoneTransform_t *pTransforms,
666
uint32_t unTransformCount)
667
{
668
+
if (eMotionRange != vr::VRSkeletalMotionRange_WithoutController) {
669
+
return vr::VRInputError_None;
670
+
}
671
+
672
+
if (!update_component_common(ulComponent, 0)) {
673
+
return vr::VRInputError_InvalidHandle;
674
+
}
675
+
676
+
auto *device = skeleton_to_controller[ulComponent];
677
+
if (!device) {
678
+
CTX_ERR("Got unknown component handle %lu", ulComponent);
679
+
return vr::VRInputError_InvalidHandle;
680
+
}
681
+
682
+
device->update_skeleton_transforms(std::span(pTransforms, unTransformCount));
683
+
684
return vr::VRInputError_None;
685
}
686
···
777
out_roles->left = left;
778
out_roles->right = right;
779
out_roles->gamepad = gamepad;
780
+
781
+
if (left != XRT_DEVICE_ROLE_UNASSIGNED) {
782
+
auto *left_dev = static_cast<ControllerDevice *>(xsysd->xdevs[left]);
783
+
left_dev->set_active_hand(XRT_HAND_LEFT);
784
+
}
785
+
786
+
if (right != XRT_DEVICE_ROLE_UNASSIGNED) {
787
+
auto *right_dev = static_cast<ControllerDevice *>(xsysd->xdevs[right]);
788
+
right_dev->set_active_hand(XRT_HAND_RIGHT);
789
+
}
790
}
791
792
return XRT_SUCCESS;
+2
src/xrt/drivers/survive/survive_driver.c
+2
src/xrt/drivers/survive/survive_driver.c
···
530
survive_device_get_view_poses(struct xrt_device *xdev,
531
const struct xrt_vec3 *default_eye_relation,
532
int64_t at_timestamp_ns,
533
uint32_t view_count,
534
struct xrt_space_relation *out_head_relation,
535
struct xrt_fov *out_fovs,
···
554
xdev, //
555
&eye_relation, //
556
at_timestamp_ns, //
557
view_count, //
558
out_head_relation, //
559
out_fovs, //
···
530
survive_device_get_view_poses(struct xrt_device *xdev,
531
const struct xrt_vec3 *default_eye_relation,
532
int64_t at_timestamp_ns,
533
+
enum xrt_view_type view_type,
534
uint32_t view_count,
535
struct xrt_space_relation *out_head_relation,
536
struct xrt_fov *out_fovs,
···
555
xdev, //
556
&eye_relation, //
557
at_timestamp_ns, //
558
+
view_type, //
559
view_count, //
560
out_head_relation, //
561
out_fovs, //
+1
-4
src/xrt/drivers/twrap/twrap_slam.c
+1
-4
src/xrt/drivers/twrap/twrap_slam.c
···
159
160
161
162
-
dx->base.update_inputs = u_device_noop_update_inputs;
163
-
dx->base.get_tracked_pose = twrap_slam_get_tracked_pose;
164
-
dx->base.get_view_poses = u_device_ni_get_view_poses;
165
-
dx->base.destroy = twrap_slam_destroy;
166
dx->base.name = name;
167
dx->base.tracking_origin->type = XRT_TRACKING_TYPE_OTHER;
168
dx->base.inputs[0].name = XRT_INPUT_GENERIC_TRACKER_POSE;
+2
src/xrt/drivers/vive/vive_device.c
+2
src/xrt/drivers/vive/vive_device.c
···
212
vive_device_get_view_poses(struct xrt_device *xdev,
213
const struct xrt_vec3 *default_eye_relation,
214
int64_t at_timestamp_ns,
215
uint32_t view_count,
216
struct xrt_space_relation *out_head_relation,
217
struct xrt_fov *out_fovs,
···
226
xdev, //
227
default_eye_relation, //
228
at_timestamp_ns, //
229
view_count, //
230
out_head_relation, //
231
out_fovs, //
···
212
vive_device_get_view_poses(struct xrt_device *xdev,
213
const struct xrt_vec3 *default_eye_relation,
214
int64_t at_timestamp_ns,
215
+
enum xrt_view_type view_type,
216
uint32_t view_count,
217
struct xrt_space_relation *out_head_relation,
218
struct xrt_fov *out_fovs,
···
227
xdev, //
228
default_eye_relation, //
229
at_timestamp_ns, //
230
+
view_type, //
231
view_count, //
232
out_head_relation, //
233
out_fovs, //
+1
-1
src/xrt/drivers/vp2/vp2_hid.c
+1
-1
src/xrt/drivers/vp2/vp2_hid.c
+4
-2
src/xrt/drivers/wmr/wmr_controller_base.c
+4
-2
src/xrt/drivers/wmr/wmr_controller_base.c
···
526
wmr_controller_base_init(struct wmr_controller_base *wcb,
527
struct wmr_controller_connection *conn,
528
enum xrt_device_type controller_type,
529
-
enum u_logging_level log_level)
530
{
531
DRV_TRACE_MARKER();
532
···
544
snprintf(wcb->base.serial, XRT_DEVICE_NAME_LEN, "Right Controller");
545
}
546
547
-
wcb->base.get_tracked_pose = wmr_controller_base_get_tracked_pose;
548
549
wcb->base.name = XRT_DEVICE_WMR_CONTROLLER;
550
wcb->base.device_type = controller_type;
···
526
wmr_controller_base_init(struct wmr_controller_base *wcb,
527
struct wmr_controller_connection *conn,
528
enum xrt_device_type controller_type,
529
+
enum u_logging_level log_level,
530
+
u_device_destroy_function_t destroy_fn)
531
{
532
DRV_TRACE_MARKER();
533
···
545
snprintf(wcb->base.serial, XRT_DEVICE_NAME_LEN, "Right Controller");
546
}
547
548
+
// Set all functions.
549
+
u_device_populate_function_pointers(&wcb->base, wmr_controller_base_get_tracked_pose, destroy_fn);
550
551
wcb->base.name = XRT_DEVICE_WMR_CONTROLLER;
552
wcb->base.device_type = controller_type;
+3
-1
src/xrt/drivers/wmr/wmr_controller_base.h
+3
-1
src/xrt/drivers/wmr/wmr_controller_base.h
···
16
17
#include "os/os_threading.h"
18
#include "math/m_imu_3dof.h"
19
#include "util/u_logging.h"
20
#include "xrt/xrt_device.h"
21
···
129
wmr_controller_base_init(struct wmr_controller_base *wcb,
130
struct wmr_controller_connection *conn,
131
enum xrt_device_type controller_type,
132
-
enum u_logging_level log_level);
133
134
void
135
wmr_controller_base_deinit(struct wmr_controller_base *wcb);
···
16
17
#include "os/os_threading.h"
18
#include "math/m_imu_3dof.h"
19
+
#include "util/u_device.h"
20
#include "util/u_logging.h"
21
#include "xrt/xrt_device.h"
22
···
130
wmr_controller_base_init(struct wmr_controller_base *wcb,
131
struct wmr_controller_connection *conn,
132
enum xrt_device_type controller_type,
133
+
enum u_logging_level log_level,
134
+
u_device_destroy_function_t destroy_fn);
135
136
void
137
wmr_controller_base_deinit(struct wmr_controller_base *wcb);
+3
-5
src/xrt/drivers/wmr/wmr_controller_hp.c
+3
-5
src/xrt/drivers/wmr/wmr_controller_hp.c
···
360
U_DEVICE_ALLOCATE(struct wmr_controller_hp, flags, WMR_CONTROLLER_INDEX_COUNT, 1);
361
struct wmr_controller_base *wcb = (struct wmr_controller_base *)(ctrl);
362
363
-
if (!wmr_controller_base_init(wcb, conn, controller_type, log_level)) {
364
wmr_controller_hp_destroy(&wcb->base);
365
return NULL;
366
}
367
368
wcb->handle_input_packet = handle_input_packet;
369
370
wcb->base.name = XRT_DEVICE_HP_REVERB_G2_CONTROLLER;
371
372
if (controller_type == XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER) {
···
374
} else {
375
snprintf(wcb->base.str, ARRAY_SIZE(wcb->base.str), "HP Reverb G2 Right Controller");
376
}
377
-
378
-
wcb->base.destroy = wmr_controller_hp_destroy;
379
-
wcb->base.update_inputs = wmr_controller_hp_update_inputs;
380
-
wcb->base.set_output = u_device_ni_set_output;
381
382
SET_INPUT(wcb, MENU_CLICK, MENU_CLICK);
383
SET_INPUT(wcb, HOME_CLICK, HOME_CLICK);
···
360
U_DEVICE_ALLOCATE(struct wmr_controller_hp, flags, WMR_CONTROLLER_INDEX_COUNT, 1);
361
struct wmr_controller_base *wcb = (struct wmr_controller_base *)(ctrl);
362
363
+
if (!wmr_controller_base_init(wcb, conn, controller_type, log_level, wmr_controller_hp_destroy)) {
364
wmr_controller_hp_destroy(&wcb->base);
365
return NULL;
366
}
367
368
wcb->handle_input_packet = handle_input_packet;
369
370
+
// Only set those we want to overwrite.
371
+
wcb->base.update_inputs = wmr_controller_hp_update_inputs;
372
wcb->base.name = XRT_DEVICE_HP_REVERB_G2_CONTROLLER;
373
374
if (controller_type == XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER) {
···
376
} else {
377
snprintf(wcb->base.str, ARRAY_SIZE(wcb->base.str), "HP Reverb G2 Right Controller");
378
}
379
380
SET_INPUT(wcb, MENU_CLICK, MENU_CLICK);
381
SET_INPUT(wcb, HOME_CLICK, HOME_CLICK);
+4
-4
src/xrt/drivers/wmr/wmr_controller_og.c
+4
-4
src/xrt/drivers/wmr/wmr_controller_og.c
···
413
struct wmr_controller_og *ctrl = U_DEVICE_ALLOCATE(struct wmr_controller_og, flags, 11, 1);
414
struct wmr_controller_base *wcb = (struct wmr_controller_base *)(ctrl);
415
416
-
if (!wmr_controller_base_init(wcb, conn, controller_type, log_level)) {
417
wmr_controller_og_destroy(&wcb->base);
418
return NULL;
419
}
420
421
wcb->handle_input_packet = handle_input_packet;
422
423
if (pid == ODYSSEY_CONTROLLER_PID) {
424
wcb->base.name = XRT_DEVICE_SAMSUNG_ODYSSEY_CONTROLLER;
425
} else {
426
wcb->base.name = XRT_DEVICE_WMR_CONTROLLER;
427
}
428
-
wcb->base.destroy = wmr_controller_og_destroy;
429
-
wcb->base.update_inputs = wmr_controller_og_update_inputs;
430
-
wcb->base.set_output = u_device_ni_set_output;
431
432
if (pid == ODYSSEY_CONTROLLER_PID) {
433
SET_ODYSSEY_INPUT(wcb, MENU_CLICK);
···
413
struct wmr_controller_og *ctrl = U_DEVICE_ALLOCATE(struct wmr_controller_og, flags, 11, 1);
414
struct wmr_controller_base *wcb = (struct wmr_controller_base *)(ctrl);
415
416
+
if (!wmr_controller_base_init(wcb, conn, controller_type, log_level, wmr_controller_og_destroy)) {
417
wmr_controller_og_destroy(&wcb->base);
418
return NULL;
419
}
420
421
wcb->handle_input_packet = handle_input_packet;
422
423
+
// Only set those we want to overwrite.
424
+
wcb->base.update_inputs = wmr_controller_og_update_inputs;
425
+
426
if (pid == ODYSSEY_CONTROLLER_PID) {
427
wcb->base.name = XRT_DEVICE_SAMSUNG_ODYSSEY_CONTROLLER;
428
} else {
429
wcb->base.name = XRT_DEVICE_WMR_CONTROLLER;
430
}
431
432
if (pid == ODYSSEY_CONTROLLER_PID) {
433
SET_ODYSSEY_INPUT(wcb, MENU_CLICK);
+12
src/xrt/drivers/wmr/wmr_hmd.c
+12
src/xrt/drivers/wmr/wmr_hmd.c
···
1947
wh->base.compute_distortion = compute_distortion_wmr;
1948
u_distortion_mesh_fill_in_compute(&wh->base);
1949
1950
+
// Set HMD Scanout direction and time
1951
+
if (wh->hmd_desc->hmd_type == WMR_HEADSET_SAMSUNG_800ZAA ||
1952
+
wh->hmd_desc->hmd_type == WMR_HEADSET_SAMSUNG_XE700X3AI) {
1953
+
1954
+
wh->base.hmd->screens[0].scanout_direction = XRT_SCANOUT_DIRECTION_TOP_TO_BOTTOM;
1955
+
wh->base.hmd->screens[0].scanout_time_ns =
1956
+
wh->base.hmd->screens[0].nominal_frame_interval_ns * 1600.0 / 1624.0;
1957
+
} else {
1958
+
wh->base.hmd->screens[0].scanout_direction = XRT_SCANOUT_DIRECTION_NONE;
1959
+
wh->base.hmd->screens[0].scanout_time_ns = 0;
1960
+
}
1961
+
1962
// Set initial HMD screen power state.
1963
wh->hmd_screen_enable = true;
1964
+49
-29
src/xrt/include/xrt/xrt_compositor.h
+49
-29
src/xrt/include/xrt/xrt_compositor.h
···
1
// Copyright 2019-2024, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
858
*
859
*/
860
861
-
/*!
862
-
* View type to be rendered to by the compositor.
863
-
*/
864
-
enum xrt_view_type
865
-
{
866
-
XRT_VIEW_TYPE_MONO = 1,
867
-
XRT_VIEW_TYPE_STEREO = 2,
868
-
};
869
-
870
enum xrt_compositor_frame_point
871
{
872
XRT_COMPOSITOR_FRAME_POINT_WOKE, //!< The client woke up after waiting.
···
974
bool fb_face_tracking2_enabled;
975
bool meta_body_tracking_full_body_enabled;
976
bool meta_body_tracking_calibration_enabled;
977
};
978
979
/*!
···
1046
struct xrt_compositor_fence **out_xcf);
1047
1048
/*!
1049
-
* Create a compositor semaphore, also returns a native handle.
1050
*/
1051
xrt_result_t (*create_semaphore)(struct xrt_compositor *xc,
1052
xrt_graphics_sync_handle_t *out_handle,
···
2291
*xcn_ptr = NULL;
2292
}
2293
2294
2295
/*
2296
*
···
2304
*/
2305
struct xrt_system_compositor_info
2306
{
2307
-
struct
2308
-
{
2309
-
struct
2310
-
{
2311
-
uint32_t width_pixels;
2312
-
uint32_t height_pixels;
2313
-
uint32_t sample_count;
2314
-
} recommended; //!< Recommended for this view.
2315
-
2316
-
struct
2317
-
{
2318
-
uint32_t width_pixels;
2319
-
uint32_t height_pixels;
2320
-
uint32_t sample_count;
2321
-
} max; //!< Maximums for this view.
2322
-
} views[XRT_MAX_VIEWS]; //!< View configuration information.
2323
2324
//! Maximum number of composition layers supported, never changes.
2325
uint32_t max_layers;
···
2373
xrt_result_t (*set_state)(struct xrt_system_compositor *xsc,
2374
struct xrt_compositor *xc,
2375
bool visible,
2376
-
bool focused);
2377
2378
/*!
2379
* Set the rendering Z order for rendering, visible has higher priority
···
2473
* @public @memberof xrt_system_compositor
2474
*/
2475
static inline xrt_result_t
2476
-
xrt_syscomp_set_state(struct xrt_system_compositor *xsc, struct xrt_compositor *xc, bool visible, bool focused)
2477
{
2478
if (xsc->xmcc == NULL) {
2479
return XRT_ERROR_MULTI_SESSION_NOT_IMPLEMENTED;
2480
}
2481
2482
-
return xsc->xmcc->set_state(xsc, xc, visible, focused);
2483
}
2484
2485
/*!
···
1
// Copyright 2019-2024, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
859
*
860
*/
861
862
enum xrt_compositor_frame_point
863
{
864
XRT_COMPOSITOR_FRAME_POINT_WOKE, //!< The client woke up after waiting.
···
966
bool fb_face_tracking2_enabled;
967
bool meta_body_tracking_full_body_enabled;
968
bool meta_body_tracking_calibration_enabled;
969
+
bool android_face_tracking_enabled;
970
};
971
972
/*!
···
1039
struct xrt_compositor_fence **out_xcf);
1040
1041
/*!
1042
+
* Create a compositor semaphore, also returns a native handle of the
1043
+
* semaphore which is owned by the @ref xrt_compositor_semaphore struct.
1044
+
* The return values are always both valid, or on an error condition
1045
+
* encountered and error is returned, both not valid (untouched).
1046
+
*
1047
+
* @param[in] xc Compositor self pointer.
1048
+
* @param[out] out_handle Native handle owned by the samephore.
1049
+
* @param[out] out_handle Return of the created semahpore.
1050
*/
1051
xrt_result_t (*create_semaphore)(struct xrt_compositor *xc,
1052
xrt_graphics_sync_handle_t *out_handle,
···
2291
*xcn_ptr = NULL;
2292
}
2293
2294
+
/*!
2295
+
* Holds information about the view configuration properties for a view in a system compositor.
2296
+
*/
2297
+
struct xrt_view_config_properties
2298
+
{
2299
+
struct
2300
+
{
2301
+
uint32_t width_pixels;
2302
+
uint32_t height_pixels;
2303
+
uint32_t sample_count;
2304
+
} recommended; //!< Recommended for this view.
2305
+
2306
+
struct
2307
+
{
2308
+
uint32_t width_pixels;
2309
+
uint32_t height_pixels;
2310
+
uint32_t sample_count;
2311
+
} max; //!< Maximums for this view.
2312
+
};
2313
+
2314
+
struct xrt_view_config
2315
+
{
2316
+
//! Which view type this is for, mono, stereo, quad_with_inset, etc...
2317
+
enum xrt_view_type view_type;
2318
+
2319
+
//! Must match the view_type, in the future view_types might have variable views.
2320
+
uint32_t view_count;
2321
+
2322
+
//! The per view information.
2323
+
struct xrt_view_config_properties views[XRT_MAX_COMPOSITOR_VIEW_CONFIGS_VIEW_COUNT];
2324
+
};
2325
+
2326
2327
/*
2328
*
···
2336
*/
2337
struct xrt_system_compositor_info
2338
{
2339
+
uint32_t view_config_count;
2340
+
struct xrt_view_config view_configs[XRT_MAX_COMPOSITOR_VIEW_CONFIGS_COUNT];
2341
2342
//! Maximum number of composition layers supported, never changes.
2343
uint32_t max_layers;
···
2391
xrt_result_t (*set_state)(struct xrt_system_compositor *xsc,
2392
struct xrt_compositor *xc,
2393
bool visible,
2394
+
bool focused,
2395
+
int64_t timestamp_ns);
2396
2397
/*!
2398
* Set the rendering Z order for rendering, visible has higher priority
···
2492
* @public @memberof xrt_system_compositor
2493
*/
2494
static inline xrt_result_t
2495
+
xrt_syscomp_set_state(
2496
+
struct xrt_system_compositor *xsc, struct xrt_compositor *xc, bool visible, bool focused, int64_t timestamp_ns)
2497
{
2498
if (xsc->xmcc == NULL) {
2499
return XRT_ERROR_MULTI_SESSION_NOT_IMPLEMENTED;
2500
}
2501
2502
+
return xsc->xmcc->set_state(xsc, xc, visible, focused, timestamp_ns);
2503
}
2504
2505
/*!
+1
src/xrt/include/xrt/xrt_config_build.h.cmake_in
+1
src/xrt/include/xrt/xrt_config_build.h.cmake_in
···
37
#cmakedefine XRT_FEATURE_OPENXR_BODY_TRACKING_FULL_BODY_META
38
#cmakedefine XRT_FEATURE_OPENXR_DEBUG_UTILS
39
#cmakedefine XRT_FEATURE_OPENXR_DISPLAY_REFRESH_RATE
40
#cmakedefine XRT_FEATURE_OPENXR_FACE_TRACKING2_FB
41
#cmakedefine XRT_FEATURE_OPENXR_FACIAL_TRACKING_HTC
42
#cmakedefine XRT_FEATURE_OPENXR_FORCE_FEEDBACK_CURL
···
37
#cmakedefine XRT_FEATURE_OPENXR_BODY_TRACKING_FULL_BODY_META
38
#cmakedefine XRT_FEATURE_OPENXR_DEBUG_UTILS
39
#cmakedefine XRT_FEATURE_OPENXR_DISPLAY_REFRESH_RATE
40
+
#cmakedefine XRT_FEATURE_OPENXR_FACE_TRACKING_ANDROID
41
#cmakedefine XRT_FEATURE_OPENXR_FACE_TRACKING2_FB
42
#cmakedefine XRT_FEATURE_OPENXR_FACIAL_TRACKING_HTC
43
#cmakedefine XRT_FEATURE_OPENXR_FORCE_FEEDBACK_CURL
+307
-131
src/xrt/include/xrt/xrt_defines.h
+307
-131
src/xrt/include/xrt/xrt_defines.h
···
1
// Copyright 2019-2024, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
715
*
716
*/
717
718
/*!
719
* A enum that is used to name devices so that the
720
* state trackers can reason about the devices easier.
721
*/
722
enum xrt_device_name
723
{
724
-
XRT_DEVICE_INVALID = 0,
725
-
726
-
XRT_DEVICE_GENERIC_HMD = 1,
727
-
728
-
// Vive stuff.
729
-
XRT_DEVICE_VIVE_PRO,
730
-
XRT_DEVICE_VIVE_WAND,
731
-
XRT_DEVICE_VIVE_TRACKER, // Generic, only used for bindings.
732
-
XRT_DEVICE_VIVE_TRACKER_GEN1,
733
-
XRT_DEVICE_VIVE_TRACKER_GEN2,
734
-
XRT_DEVICE_VIVE_TRACKER_GEN3,
735
-
XRT_DEVICE_VIVE_TRACKER_TUNDRA,
736
737
-
// "Controllers" somewhat sorted as listed in spec.
738
-
XRT_DEVICE_SIMPLE_CONTROLLER,
739
-
XRT_DEVICE_DAYDREAM,
740
-
XRT_DEVICE_WMR_CONTROLLER,
741
-
XRT_DEVICE_XBOX_CONTROLLER,
742
-
XRT_DEVICE_GO_CONTROLLER,
743
-
XRT_DEVICE_TOUCH_CONTROLLER,
744
-
XRT_DEVICE_INDEX_CONTROLLER,
745
746
-
XRT_DEVICE_HP_REVERB_G2_CONTROLLER,
747
-
XRT_DEVICE_SAMSUNG_ODYSSEY_CONTROLLER,
748
-
XRT_DEVICE_ML2_CONTROLLER,
749
-
XRT_DEVICE_OPPO_MR_CONTROLLER,
750
-
751
-
XRT_DEVICE_HAND_INTERACTION,
752
-
753
-
XRT_DEVICE_EYE_GAZE_INTERACTION,
754
-
755
-
XRT_DEVICE_PSMV,
756
-
XRT_DEVICE_PSSENSE,
757
-
XRT_DEVICE_HYDRA,
758
-
XRT_DEVICE_RIFT_REMOTE,
759
-
XRT_DEVICE_BLUBUR_S1,
760
-
XRT_DEVICE_PSVR2,
761
-
762
-
// Other misc stuff.
763
-
XRT_DEVICE_HAND_TRACKER,
764
-
XRT_DEVICE_REALSENSE,
765
-
XRT_DEVICE_DEPTHAI,
766
-
767
-
//! XR_EXT_hand_interaction
768
-
XRT_DEVICE_EXT_HAND_INTERACTION,
769
-
770
-
//! XR_HTC_facial_tracking
771
-
XRT_DEVICE_HTC_FACE_TRACKING,
772
-
773
-
//! XR_FB_body_tracking
774
-
XRT_DEVICE_FB_BODY_TRACKING,
775
-
776
-
//! XR_FB_face_tracking2
777
-
XRT_DEVICE_FB_FACE_TRACKING2,
778
-
779
-
// added in OpenXR 1.1
780
-
XRT_DEVICE_PICO_NEO3_CONTROLLER,
781
-
XRT_DEVICE_PICO4_CONTROLLER,
782
-
XRT_DEVICE_PICO_G3_CONTROLLER,
783
-
784
-
XRT_DEVICE_VIVE_COSMOS_CONTROLLER,
785
-
XRT_DEVICE_VIVE_FOCUS3_CONTROLLER,
786
-
787
-
XRT_DEVICE_TOUCH_PRO_CONTROLLER,
788
-
XRT_DEVICE_TOUCH_PLUS_CONTROLLER,
789
-
XRT_DEVICE_TOUCH_CONTROLLER_RIFT_CV1,
790
-
XRT_DEVICE_TOUCH_CONTROLLER_QUEST_1_RIFT_S,
791
-
XRT_DEVICE_TOUCH_CONTROLLER_QUEST_2,
792
};
793
794
/*!
···
1117
_(XRT_INPUT_PSSENSE_CIRCLE_TOUCH , XRT_INPUT_NAME(0x030a, BOOLEAN)) \
1118
_(XRT_INPUT_PSSENSE_SQUEEZE_CLICK , XRT_INPUT_NAME(0x030b, BOOLEAN)) \
1119
_(XRT_INPUT_PSSENSE_SQUEEZE_TOUCH , XRT_INPUT_NAME(0x030c, BOOLEAN)) \
1120
-
_(XRT_INPUT_PSSENSE_SQUEEZE_PROXIMITY , XRT_INPUT_NAME(0x030d, VEC1_ZERO_TO_ONE)) \
1121
-
_(XRT_INPUT_PSSENSE_TRIGGER_CLICK , XRT_INPUT_NAME(0x030e, BOOLEAN)) \
1122
-
_(XRT_INPUT_PSSENSE_TRIGGER_TOUCH , XRT_INPUT_NAME(0x030f, BOOLEAN)) \
1123
-
_(XRT_INPUT_PSSENSE_TRIGGER_VALUE , XRT_INPUT_NAME(0x0310, VEC1_ZERO_TO_ONE)) \
1124
-
_(XRT_INPUT_PSSENSE_TRIGGER_PROXIMITY , XRT_INPUT_NAME(0x0311, VEC1_ZERO_TO_ONE)) \
1125
-
_(XRT_INPUT_PSSENSE_THUMBSTICK , XRT_INPUT_NAME(0x0312, VEC2_MINUS_ONE_TO_ONE)) \
1126
-
_(XRT_INPUT_PSSENSE_THUMBSTICK_CLICK , XRT_INPUT_NAME(0x0313, BOOLEAN)) \
1127
-
_(XRT_INPUT_PSSENSE_THUMBSTICK_TOUCH , XRT_INPUT_NAME(0x0314, BOOLEAN)) \
1128
-
_(XRT_INPUT_PSSENSE_GRIP_POSE , XRT_INPUT_NAME(0x0315, POSE)) \
1129
-
_(XRT_INPUT_PSSENSE_AIM_POSE , XRT_INPUT_NAME(0x0316, POSE)) \
1130
\
1131
/** XR_EXT_hand_interaction */ \
1132
_(XRT_INPUT_HAND_PINCH_POSE , XRT_INPUT_NAME(0x0401, POSE)) \
···
1164
_(XRT_INPUT_HTC_LIP_FACE_TRACKING , XRT_INPUT_NAME(0x0602, FACE_TRACKING)) \
1165
_(XRT_INPUT_FB_FACE_TRACKING2_AUDIO , XRT_INPUT_NAME(0x0603, FACE_TRACKING)) \
1166
_(XRT_INPUT_FB_FACE_TRACKING2_VISUAL , XRT_INPUT_NAME(0x0604, FACE_TRACKING)) \
1167
\
1168
_(XRT_INPUT_GENERIC_BODY_TRACKING , XRT_INPUT_NAME(0x0700, BODY_TRACKING)) \
1169
_(XRT_INPUT_FB_BODY_TRACKING , XRT_INPUT_NAME(0x0701, BODY_TRACKING)) \
···
1318
\
1319
_(XRT_INPUT_BLUBUR_S1_MENU_CLICK , XRT_INPUT_NAME(0x1000, BOOLEAN)) \
1320
\
1321
-
_(XRT_INPUT_PSVR2_SYSTEM_CLICK , XRT_INPUT_NAME(0x1100, BOOLEAN))
1322
-
1323
-
1324
// clang-format on
1325
1326
···
1470
#define XRT_OUTPUT_TYPE_BITMASK 0xffu
1471
1472
/*!
1473
* Base type of this output.
1474
*
1475
* @ingroup xrt_iface
···
1482
// clang-format on
1483
};
1484
1485
-
#define XRT_OUTPUT_NAME(id, type) ((UINT32_C(id) << XRT_OUTPUT_TYPE_BITWIDTH) | (uint32_t)XRT_OUTPUT_TYPE_##type)
1486
1487
enum xrt_face_expression2_fb
1488
{
···
1649
#define XRT_FACIAL_EXPRESSION_EYE_COUNT_HTC 14
1650
#define XRT_FACIAL_EXPRESSION_LIP_COUNT_HTC 37
1651
1652
struct xrt_facial_base_expression_set_htc
1653
{
1654
int64_t sample_time_ns;
···
1681
bool is_eye_following_blendshapes_valid;
1682
};
1683
1684
struct xrt_facial_expression_set
1685
{
1686
union {
···
1688
struct xrt_facial_eye_expression_set_htc eye_expression_set_htc;
1689
struct xrt_facial_lip_expression_set_htc lip_expression_set_htc;
1690
struct xrt_facial_expression_set2_fb face_expression_set2_fb;
1691
};
1692
};
1693
···
1958
};
1959
1960
/*!
1961
-
* Name of a output with a baked in type.
1962
-
*
1963
-
* @see xrt_output_type
1964
-
* @ingroup xrt_iface
1965
-
*/
1966
-
enum xrt_output_name
1967
-
{
1968
-
// clang-format off
1969
-
XRT_OUTPUT_NAME_SIMPLE_VIBRATION = XRT_OUTPUT_NAME(0x0010, VIBRATION),
1970
-
XRT_OUTPUT_NAME_PSMV_RUMBLE_VIBRATION = XRT_OUTPUT_NAME(0x0020, VIBRATION),
1971
-
XRT_OUTPUT_NAME_INDEX_HAPTIC = XRT_OUTPUT_NAME(0x0030, VIBRATION),
1972
-
XRT_OUTPUT_NAME_VIVE_HAPTIC = XRT_OUTPUT_NAME(0x0040, VIBRATION),
1973
-
XRT_OUTPUT_NAME_WMR_HAPTIC = XRT_OUTPUT_NAME(0x0050, VIBRATION),
1974
-
1975
-
XRT_OUTPUT_NAME_XBOX_HAPTIC_LEFT = XRT_OUTPUT_NAME(0x0060, VIBRATION),
1976
-
XRT_OUTPUT_NAME_XBOX_HAPTIC_RIGHT = XRT_OUTPUT_NAME(0x0061, VIBRATION),
1977
-
XRT_OUTPUT_NAME_XBOX_HAPTIC_LEFT_TRIGGER = XRT_OUTPUT_NAME(0x0062, VIBRATION),
1978
-
XRT_OUTPUT_NAME_XBOX_HAPTIC_RIGHT_TRIGGER = XRT_OUTPUT_NAME(0x0063, VIBRATION),
1979
-
1980
-
XRT_OUTPUT_NAME_TOUCH_HAPTIC = XRT_OUTPUT_NAME(0x0070, VIBRATION),
1981
-
1982
-
XRT_OUTPUT_NAME_FORCE_FEEDBACK_LEFT = XRT_OUTPUT_NAME(0x0080, FORCE_FEEDBACK),
1983
-
XRT_OUTPUT_NAME_FORCE_FEEDBACK_RIGHT = XRT_OUTPUT_NAME(0x0081, FORCE_FEEDBACK),
1984
-
1985
-
XRT_OUTPUT_NAME_G2_CONTROLLER_HAPTIC = XRT_OUTPUT_NAME(0x0090, VIBRATION),
1986
-
XRT_OUTPUT_NAME_ODYSSEY_CONTROLLER_HAPTIC = XRT_OUTPUT_NAME(0x00A0, VIBRATION),
1987
-
XRT_OUTPUT_NAME_ML2_CONTROLLER_VIBRATION = XRT_OUTPUT_NAME(0x00B0, VIBRATION),
1988
-
1989
-
XRT_OUTPUT_NAME_PSSENSE_VIBRATION = XRT_OUTPUT_NAME(0x00C0, VIBRATION),
1990
-
XRT_OUTPUT_NAME_PSSENSE_TRIGGER_FEEDBACK = XRT_OUTPUT_NAME(0x00C1, FORCE_FEEDBACK),
1991
-
1992
-
XRT_OUTPUT_NAME_VIVE_TRACKER_HAPTIC = XRT_OUTPUT_NAME(0x00D0, VIBRATION),
1993
-
1994
-
XRT_OUTPUT_NAME_OPPO_MR_HAPTIC = XRT_OUTPUT_NAME(0x00E0, VIBRATION),
1995
-
1996
-
XRT_OUTPUT_NAME_PICO_NEO3_HAPTIC = XRT_OUTPUT_NAME(0x00F0, VIBRATION),
1997
-
XRT_OUTPUT_NAME_PICO4_HAPTIC = XRT_OUTPUT_NAME(0x0100, VIBRATION),
1998
-
1999
-
XRT_OUTPUT_NAME_VIVE_COSMOS_HAPTIC = XRT_OUTPUT_NAME(0x0200, VIBRATION),
2000
-
XRT_OUTPUT_NAME_VIVE_FOCUS3_HAPTIC = XRT_OUTPUT_NAME(0x0300, VIBRATION),
2001
-
2002
-
XRT_OUTPUT_NAME_TOUCH_PRO_HAPTIC = XRT_OUTPUT_NAME(0x0400, VIBRATION),
2003
-
XRT_OUTPUT_NAME_TOUCH_PRO_HAPTIC_TRIGGER = XRT_OUTPUT_NAME(0x0500, VIBRATION),
2004
-
XRT_OUTPUT_NAME_TOUCH_PRO_HAPTIC_THUMB = XRT_OUTPUT_NAME(0x0600, VIBRATION),
2005
-
XRT_OUTPUT_NAME_TOUCH_PLUS_HAPTIC = XRT_OUTPUT_NAME(0x0700, VIBRATION),
2006
-
2007
-
XRT_OUTPUT_NAME_PSVR2_HAPTIC = XRT_OUTPUT_NAME(0x0800, VIBRATION),
2008
-
// clang-format on
2009
-
};
2010
-
2011
-
/*!
2012
* Value used to indicate a haptic pulse of the minimal supported duration.
2013
*
2014
* @ingroup xrt_iface
···
2107
{
2108
XRT_FORM_FACTOR_HMD, //!< Head mounted display.
2109
XRT_FORM_FACTOR_HANDHELD, //!< Handheld display.
2110
};
2111
2112
/*!
···
1
// Copyright 2019-2024, Collabora, Ltd.
2
+
// Copyright 2024-2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
716
*
717
*/
718
719
+
// clang-format off
720
+
#define XRT_DEVICE_NAME_LIST(_) \
721
+
_(XRT_DEVICE_INVALID) \
722
+
\
723
+
_(XRT_DEVICE_GENERIC_HMD) \
724
+
\
725
+
/* Vive stuff. */ \
726
+
_(XRT_DEVICE_VIVE_PRO) \
727
+
_(XRT_DEVICE_VIVE_WAND) \
728
+
_(XRT_DEVICE_VIVE_TRACKER) /* Generic, only used for bindings. */ \
729
+
_(XRT_DEVICE_VIVE_TRACKER_GEN1) \
730
+
_(XRT_DEVICE_VIVE_TRACKER_GEN2) \
731
+
_(XRT_DEVICE_VIVE_TRACKER_GEN3) \
732
+
_(XRT_DEVICE_VIVE_TRACKER_TUNDRA) \
733
+
\
734
+
/* "Controllers" somewhat sorted as listed in spec. */\
735
+
_(XRT_DEVICE_SIMPLE_CONTROLLER) \
736
+
_(XRT_DEVICE_DAYDREAM) \
737
+
_(XRT_DEVICE_WMR_CONTROLLER) \
738
+
_(XRT_DEVICE_XBOX_CONTROLLER) \
739
+
_(XRT_DEVICE_GO_CONTROLLER) \
740
+
_(XRT_DEVICE_TOUCH_CONTROLLER) \
741
+
_(XRT_DEVICE_INDEX_CONTROLLER) \
742
+
\
743
+
_(XRT_DEVICE_HP_REVERB_G2_CONTROLLER) \
744
+
_(XRT_DEVICE_SAMSUNG_ODYSSEY_CONTROLLER) \
745
+
_(XRT_DEVICE_ML2_CONTROLLER) \
746
+
_(XRT_DEVICE_OPPO_MR_CONTROLLER) \
747
+
\
748
+
_(XRT_DEVICE_HAND_INTERACTION) \
749
+
\
750
+
_(XRT_DEVICE_EYE_GAZE_INTERACTION) \
751
+
\
752
+
_(XRT_DEVICE_PSMV) \
753
+
_(XRT_DEVICE_PSSENSE) \
754
+
_(XRT_DEVICE_HYDRA) \
755
+
_(XRT_DEVICE_RIFT_REMOTE) \
756
+
_(XRT_DEVICE_BLUBUR_S1) \
757
+
_(XRT_DEVICE_PSVR2) \
758
+
\
759
+
/* Other misc stuff. */\
760
+
_(XRT_DEVICE_HAND_TRACKER) \
761
+
_(XRT_DEVICE_REALSENSE) \
762
+
_(XRT_DEVICE_DEPTHAI) \
763
+
\
764
+
/*! XR_EXT_hand_interaction */\
765
+
_(XRT_DEVICE_EXT_HAND_INTERACTION) \
766
+
\
767
+
/*! XR_HTC_facial_tracking */\
768
+
_(XRT_DEVICE_HTC_FACE_TRACKING) \
769
+
\
770
+
/*! XR_FB_body_tracking */\
771
+
_(XRT_DEVICE_FB_BODY_TRACKING) \
772
+
\
773
+
/*! XR_FB_face_tracking2 */\
774
+
_(XRT_DEVICE_FB_FACE_TRACKING2) \
775
+
\
776
+
/* added in OpenXR 1.1 */\
777
+
_(XRT_DEVICE_PICO_NEO3_CONTROLLER) \
778
+
_(XRT_DEVICE_PICO4_CONTROLLER) \
779
+
_(XRT_DEVICE_PICO_G3_CONTROLLER) \
780
+
\
781
+
_(XRT_DEVICE_VIVE_COSMOS_CONTROLLER) \
782
+
_(XRT_DEVICE_VIVE_FOCUS3_CONTROLLER) \
783
+
\
784
+
_(XRT_DEVICE_TOUCH_PRO_CONTROLLER) \
785
+
_(XRT_DEVICE_TOUCH_PLUS_CONTROLLER) \
786
+
_(XRT_DEVICE_TOUCH_CONTROLLER_RIFT_CV1) \
787
+
_(XRT_DEVICE_TOUCH_CONTROLLER_QUEST_1_RIFT_S) \
788
+
_(XRT_DEVICE_TOUCH_CONTROLLER_QUEST_2) \
789
+
\
790
+
/* Hand based controller emulation. */\
791
+
_(XRT_DEVICE_HAND_CTRL_EMU) \
792
+
\
793
+
/* Please keep this comment and the trailing \ to reduce lines changed when adding entries. */
794
+
// clang-format on
795
+
796
/*!
797
* A enum that is used to name devices so that the
798
* state trackers can reason about the devices easier.
799
*/
800
enum xrt_device_name
801
{
802
+
#define XRT_DEVICE_NAME_TO_ENUM(NAME) NAME,
803
804
+
XRT_DEVICE_NAME_LIST(XRT_DEVICE_NAME_TO_ENUM)
805
806
+
#undef XRT_DEVICE_NAME_TO_ENUM
807
};
808
809
/*!
···
1132
_(XRT_INPUT_PSSENSE_CIRCLE_TOUCH , XRT_INPUT_NAME(0x030a, BOOLEAN)) \
1133
_(XRT_INPUT_PSSENSE_SQUEEZE_CLICK , XRT_INPUT_NAME(0x030b, BOOLEAN)) \
1134
_(XRT_INPUT_PSSENSE_SQUEEZE_TOUCH , XRT_INPUT_NAME(0x030c, BOOLEAN)) \
1135
+
_(XRT_INPUT_PSSENSE_SQUEEZE_PROXIMITY , XRT_INPUT_NAME(0x030d, BOOLEAN)) \
1136
+
_(XRT_INPUT_PSSENSE_SQUEEZE_PROXIMITY_FLOAT , XRT_INPUT_NAME(0x030e, VEC1_ZERO_TO_ONE)) \
1137
+
_(XRT_INPUT_PSSENSE_TRIGGER_CLICK , XRT_INPUT_NAME(0x030f, BOOLEAN)) \
1138
+
_(XRT_INPUT_PSSENSE_TRIGGER_TOUCH , XRT_INPUT_NAME(0x0310, BOOLEAN)) \
1139
+
_(XRT_INPUT_PSSENSE_TRIGGER_VALUE , XRT_INPUT_NAME(0x0311, VEC1_ZERO_TO_ONE)) \
1140
+
_(XRT_INPUT_PSSENSE_TRIGGER_PROXIMITY , XRT_INPUT_NAME(0x0312, BOOLEAN)) \
1141
+
_(XRT_INPUT_PSSENSE_TRIGGER_PROXIMITY_FLOAT , XRT_INPUT_NAME(0x0313, VEC1_ZERO_TO_ONE)) \
1142
+
_(XRT_INPUT_PSSENSE_THUMBSTICK , XRT_INPUT_NAME(0x0314, VEC2_MINUS_ONE_TO_ONE)) \
1143
+
_(XRT_INPUT_PSSENSE_THUMBSTICK_CLICK , XRT_INPUT_NAME(0x0315, BOOLEAN)) \
1144
+
_(XRT_INPUT_PSSENSE_THUMBSTICK_TOUCH , XRT_INPUT_NAME(0x0316, BOOLEAN)) \
1145
+
_(XRT_INPUT_PSSENSE_GRIP_POSE , XRT_INPUT_NAME(0x0317, POSE)) \
1146
+
_(XRT_INPUT_PSSENSE_AIM_POSE , XRT_INPUT_NAME(0x0318, POSE)) \
1147
\
1148
/** XR_EXT_hand_interaction */ \
1149
_(XRT_INPUT_HAND_PINCH_POSE , XRT_INPUT_NAME(0x0401, POSE)) \
···
1181
_(XRT_INPUT_HTC_LIP_FACE_TRACKING , XRT_INPUT_NAME(0x0602, FACE_TRACKING)) \
1182
_(XRT_INPUT_FB_FACE_TRACKING2_AUDIO , XRT_INPUT_NAME(0x0603, FACE_TRACKING)) \
1183
_(XRT_INPUT_FB_FACE_TRACKING2_VISUAL , XRT_INPUT_NAME(0x0604, FACE_TRACKING)) \
1184
+
_(XRT_INPUT_ANDROID_FACE_TRACKING , XRT_INPUT_NAME(0x0605, FACE_TRACKING)) \
1185
\
1186
_(XRT_INPUT_GENERIC_BODY_TRACKING , XRT_INPUT_NAME(0x0700, BODY_TRACKING)) \
1187
_(XRT_INPUT_FB_BODY_TRACKING , XRT_INPUT_NAME(0x0701, BODY_TRACKING)) \
···
1336
\
1337
_(XRT_INPUT_BLUBUR_S1_MENU_CLICK , XRT_INPUT_NAME(0x1000, BOOLEAN)) \
1338
\
1339
+
_(XRT_INPUT_PSVR2_SYSTEM_CLICK , XRT_INPUT_NAME(0x1100, BOOLEAN)) \
1340
+
\
1341
+
_(XRT_INPUT_HAND_CTRL_EMU_PINCH_BOOL , XRT_INPUT_NAME(0x1200, BOOLEAN)) \
1342
+
_(XRT_INPUT_HAND_CTRL_EMU_PINCH_VALUE , XRT_INPUT_NAME(0x1201, VEC1_ZERO_TO_ONE)) \
1343
+
_(XRT_INPUT_HAND_CTRL_EMU_GRIP_POSE , XRT_INPUT_NAME(0x1202, POSE)) \
1344
+
_(XRT_INPUT_HAND_CTRL_EMU_AIM_POSE , XRT_INPUT_NAME(0x1203, POSE)) \
1345
+
\
1346
+
/* Please keep this comment and the trailing \ to reduce lines changed when adding entries. */
1347
// clang-format on
1348
1349
···
1493
#define XRT_OUTPUT_TYPE_BITMASK 0xffu
1494
1495
/*!
1496
+
* @brief Create an enum value for xrt_output_name that packs an ID and output
1497
+
* type.
1498
+
*
1499
+
* @param id an integer
1500
+
* @param type The suffix of an xrt_output_type value name: `XRT_OUTPUT_TYPE_` is
1501
+
* prepended automatically.
1502
+
*
1503
+
* @see xrt_output_name
1504
+
* @ingroup xrt_iface
1505
+
*/
1506
+
#define XRT_OUTPUT_NAME(id, type) ((UINT32_C(id) << XRT_OUTPUT_TYPE_BITWIDTH) | (uint32_t)XRT_OUTPUT_TYPE_##type)
1507
+
1508
+
/*!
1509
+
* @brief Extract the xrt_output_type from an xrt_output_name.
1510
+
*
1511
+
* @param name An xrt_output_name value
1512
+
*
1513
+
* @relates xrt_output_name
1514
+
* @returns @ref xrt_output_type
1515
+
* @ingroup xrt_iface
1516
+
*/
1517
+
#define XRT_GET_OUTPUT_TYPE(name) ((enum xrt_output_type)(name & XRT_OUTPUT_TYPE_BITMASK))
1518
+
1519
+
/*!
1520
+
* @brief Extract the xrt_output_name id from an xrt_output_name.
1521
+
*
1522
+
* @param name An xrt_output_name value
1523
+
*
1524
+
* @relates xrt_output_name
1525
+
* @returns The extracted id.
1526
+
* @ingroup xrt_iface
1527
+
*/
1528
+
#define XRT_GET_OUTPUT_ID(name) ((uint32_t)(name >> XRT_OUTPUT_TYPE_BITWIDTH))
1529
+
1530
+
/*!
1531
* Base type of this output.
1532
*
1533
* @ingroup xrt_iface
···
1540
// clang-format on
1541
};
1542
1543
+
// clang-format off
1544
+
#define XRT_OUTPUT_LIST(_) \
1545
+
_(XRT_OUTPUT_NAME_SIMPLE_VIBRATION , XRT_OUTPUT_NAME(0x0010, VIBRATION)) \
1546
+
_(XRT_OUTPUT_NAME_PSMV_RUMBLE_VIBRATION , XRT_OUTPUT_NAME(0x0020, VIBRATION)) \
1547
+
_(XRT_OUTPUT_NAME_INDEX_HAPTIC , XRT_OUTPUT_NAME(0x0030, VIBRATION)) \
1548
+
_(XRT_OUTPUT_NAME_VIVE_HAPTIC , XRT_OUTPUT_NAME(0x0040, VIBRATION)) \
1549
+
_(XRT_OUTPUT_NAME_WMR_HAPTIC , XRT_OUTPUT_NAME(0x0050, VIBRATION)) \
1550
+
\
1551
+
_(XRT_OUTPUT_NAME_XBOX_HAPTIC_LEFT , XRT_OUTPUT_NAME(0x0060, VIBRATION)) \
1552
+
_(XRT_OUTPUT_NAME_XBOX_HAPTIC_RIGHT , XRT_OUTPUT_NAME(0x0061, VIBRATION)) \
1553
+
_(XRT_OUTPUT_NAME_XBOX_HAPTIC_LEFT_TRIGGER , XRT_OUTPUT_NAME(0x0062, VIBRATION)) \
1554
+
_(XRT_OUTPUT_NAME_XBOX_HAPTIC_RIGHT_TRIGGER , XRT_OUTPUT_NAME(0x0063, VIBRATION)) \
1555
+
\
1556
+
_(XRT_OUTPUT_NAME_TOUCH_HAPTIC , XRT_OUTPUT_NAME(0x0070, VIBRATION)) \
1557
+
\
1558
+
_(XRT_OUTPUT_NAME_FORCE_FEEDBACK_LEFT , XRT_OUTPUT_NAME(0x0080, FORCE_FEEDBACK)) \
1559
+
_(XRT_OUTPUT_NAME_FORCE_FEEDBACK_RIGHT , XRT_OUTPUT_NAME(0x0081, FORCE_FEEDBACK)) \
1560
+
\
1561
+
_(XRT_OUTPUT_NAME_G2_CONTROLLER_HAPTIC , XRT_OUTPUT_NAME(0x0090, VIBRATION)) \
1562
+
_(XRT_OUTPUT_NAME_ODYSSEY_CONTROLLER_HAPTIC , XRT_OUTPUT_NAME(0x00A0, VIBRATION)) \
1563
+
_(XRT_OUTPUT_NAME_ML2_CONTROLLER_VIBRATION , XRT_OUTPUT_NAME(0x00B0, VIBRATION)) \
1564
+
\
1565
+
_(XRT_OUTPUT_NAME_PSSENSE_VIBRATION , XRT_OUTPUT_NAME(0x00C0, VIBRATION)) \
1566
+
_(XRT_OUTPUT_NAME_PSSENSE_TRIGGER_FEEDBACK , XRT_OUTPUT_NAME(0x00C1, FORCE_FEEDBACK)) \
1567
+
\
1568
+
_(XRT_OUTPUT_NAME_VIVE_TRACKER_HAPTIC , XRT_OUTPUT_NAME(0x00D0, VIBRATION)) \
1569
+
\
1570
+
_(XRT_OUTPUT_NAME_OPPO_MR_HAPTIC , XRT_OUTPUT_NAME(0x00E0, VIBRATION)) \
1571
+
\
1572
+
_(XRT_OUTPUT_NAME_PICO_NEO3_HAPTIC , XRT_OUTPUT_NAME(0x00F0, VIBRATION)) \
1573
+
_(XRT_OUTPUT_NAME_PICO4_HAPTIC , XRT_OUTPUT_NAME(0x0100, VIBRATION)) \
1574
+
\
1575
+
_(XRT_OUTPUT_NAME_VIVE_COSMOS_HAPTIC , XRT_OUTPUT_NAME(0x0200, VIBRATION)) \
1576
+
_(XRT_OUTPUT_NAME_VIVE_FOCUS3_HAPTIC , XRT_OUTPUT_NAME(0x0300, VIBRATION)) \
1577
+
\
1578
+
_(XRT_OUTPUT_NAME_TOUCH_PRO_HAPTIC , XRT_OUTPUT_NAME(0x0400, VIBRATION)) \
1579
+
_(XRT_OUTPUT_NAME_TOUCH_PRO_HAPTIC_TRIGGER , XRT_OUTPUT_NAME(0x0500, VIBRATION)) \
1580
+
_(XRT_OUTPUT_NAME_TOUCH_PRO_HAPTIC_THUMB , XRT_OUTPUT_NAME(0x0600, VIBRATION)) \
1581
+
_(XRT_OUTPUT_NAME_TOUCH_PLUS_HAPTIC , XRT_OUTPUT_NAME(0x0700, VIBRATION)) \
1582
+
\
1583
+
_(XRT_OUTPUT_NAME_PSVR2_HAPTIC , XRT_OUTPUT_NAME(0x0800, VIBRATION)) \
1584
+
\
1585
+
/* Please keep this comment and the trailing \ to reduce lines changed when adding entries. */
1586
+
// clang-format on
1587
+
1588
+
/*!
1589
+
* Name of a output with a baked in type.
1590
+
*
1591
+
* @see xrt_output_type
1592
+
* @ingroup xrt_iface
1593
+
*/
1594
+
enum xrt_output_name
1595
+
{
1596
+
#define XRT_OUTPUT_LIST_TO_NAME_VALUE(NAME, VALUE) NAME = VALUE,
1597
+
1598
+
XRT_OUTPUT_LIST(XRT_OUTPUT_LIST_TO_NAME_VALUE)
1599
+
1600
+
#undef XRT_OUTPUT_LIST_TO_NAME_VALUE
1601
+
};
1602
1603
enum xrt_face_expression2_fb
1604
{
···
1765
#define XRT_FACIAL_EXPRESSION_EYE_COUNT_HTC 14
1766
#define XRT_FACIAL_EXPRESSION_LIP_COUNT_HTC 37
1767
1768
+
enum xrt_face_confidence_regions_android
1769
+
{
1770
+
XRT_FACE_CONFIDENCE_REGIONS_LOWER_ANDROID = 0,
1771
+
XRT_FACE_CONFIDENCE_REGIONS_LEFT_UPPER_ANDROID = 1,
1772
+
XRT_FACE_CONFIDENCE_REGIONS_RIGHT_UPPER_ANDROID = 2,
1773
+
};
1774
+
1775
+
enum xrt_face_parameter_indices_android
1776
+
{
1777
+
XRT_FACE_PARAMETER_INDICES_BROW_LOWERER_L_ANDROID = 0,
1778
+
XRT_FACE_PARAMETER_INDICES_BROW_LOWERER_R_ANDROID = 1,
1779
+
XRT_FACE_PARAMETER_INDICES_CHEEK_PUFF_L_ANDROID = 2,
1780
+
XRT_FACE_PARAMETER_INDICES_CHEEK_PUFF_R_ANDROID = 3,
1781
+
XRT_FACE_PARAMETER_INDICES_CHEEK_RAISER_L_ANDROID = 4,
1782
+
XRT_FACE_PARAMETER_INDICES_CHEEK_RAISER_R_ANDROID = 5,
1783
+
XRT_FACE_PARAMETER_INDICES_CHEEK_SUCK_L_ANDROID = 6,
1784
+
XRT_FACE_PARAMETER_INDICES_CHEEK_SUCK_R_ANDROID = 7,
1785
+
XRT_FACE_PARAMETER_INDICES_CHIN_RAISER_B_ANDROID = 8,
1786
+
XRT_FACE_PARAMETER_INDICES_CHIN_RAISER_T_ANDROID = 9,
1787
+
XRT_FACE_PARAMETER_INDICES_DIMPLER_L_ANDROID = 10,
1788
+
XRT_FACE_PARAMETER_INDICES_DIMPLER_R_ANDROID = 11,
1789
+
XRT_FACE_PARAMETER_INDICES_EYES_CLOSED_L_ANDROID = 12,
1790
+
XRT_FACE_PARAMETER_INDICES_EYES_CLOSED_R_ANDROID = 13,
1791
+
XRT_FACE_PARAMETER_INDICES_EYES_LOOK_DOWN_L_ANDROID = 14,
1792
+
XRT_FACE_PARAMETER_INDICES_EYES_LOOK_DOWN_R_ANDROID = 15,
1793
+
XRT_FACE_PARAMETER_INDICES_EYES_LOOK_LEFT_L_ANDROID = 16,
1794
+
XRT_FACE_PARAMETER_INDICES_EYES_LOOK_LEFT_R_ANDROID = 17,
1795
+
XRT_FACE_PARAMETER_INDICES_EYES_LOOK_RIGHT_L_ANDROID = 18,
1796
+
XRT_FACE_PARAMETER_INDICES_EYES_LOOK_RIGHT_R_ANDROID = 19,
1797
+
XRT_FACE_PARAMETER_INDICES_EYES_LOOK_UP_L_ANDROID = 20,
1798
+
XRT_FACE_PARAMETER_INDICES_EYES_LOOK_UP_R_ANDROID = 21,
1799
+
XRT_FACE_PARAMETER_INDICES_INNER_BROW_RAISER_L_ANDROID = 22,
1800
+
XRT_FACE_PARAMETER_INDICES_INNER_BROW_RAISER_R_ANDROID = 23,
1801
+
XRT_FACE_PARAMETER_INDICES_JAW_DROP_ANDROID = 24,
1802
+
XRT_FACE_PARAMETER_INDICES_JAW_SIDEWAYS_LEFT_ANDROID = 25,
1803
+
XRT_FACE_PARAMETER_INDICES_JAW_SIDEWAYS_RIGHT_ANDROID = 26,
1804
+
XRT_FACE_PARAMETER_INDICES_JAW_THRUST_ANDROID = 27,
1805
+
XRT_FACE_PARAMETER_INDICES_LID_TIGHTENER_L_ANDROID = 28,
1806
+
XRT_FACE_PARAMETER_INDICES_LID_TIGHTENER_R_ANDROID = 29,
1807
+
XRT_FACE_PARAMETER_INDICES_LIP_CORNER_DEPRESSOR_L_ANDROID = 30,
1808
+
XRT_FACE_PARAMETER_INDICES_LIP_CORNER_DEPRESSOR_R_ANDROID = 31,
1809
+
XRT_FACE_PARAMETER_INDICES_LIP_CORNER_PULLER_L_ANDROID = 32,
1810
+
XRT_FACE_PARAMETER_INDICES_LIP_CORNER_PULLER_R_ANDROID = 33,
1811
+
XRT_FACE_PARAMETER_INDICES_LIP_FUNNELER_LB_ANDROID = 34,
1812
+
XRT_FACE_PARAMETER_INDICES_LIP_FUNNELER_LT_ANDROID = 35,
1813
+
XRT_FACE_PARAMETER_INDICES_LIP_FUNNELER_RB_ANDROID = 36,
1814
+
XRT_FACE_PARAMETER_INDICES_LIP_FUNNELER_RT_ANDROID = 37,
1815
+
XRT_FACE_PARAMETER_INDICES_LIP_PRESSOR_L_ANDROID = 38,
1816
+
XRT_FACE_PARAMETER_INDICES_LIP_PRESSOR_R_ANDROID = 39,
1817
+
XRT_FACE_PARAMETER_INDICES_LIP_PUCKER_L_ANDROID = 40,
1818
+
XRT_FACE_PARAMETER_INDICES_LIP_PUCKER_R_ANDROID = 41,
1819
+
XRT_FACE_PARAMETER_INDICES_LIP_STRETCHER_L_ANDROID = 42,
1820
+
XRT_FACE_PARAMETER_INDICES_LIP_STRETCHER_R_ANDROID = 43,
1821
+
XRT_FACE_PARAMETER_INDICES_LIP_SUCK_LB_ANDROID = 44,
1822
+
XRT_FACE_PARAMETER_INDICES_LIP_SUCK_LT_ANDROID = 45,
1823
+
XRT_FACE_PARAMETER_INDICES_LIP_SUCK_RB_ANDROID = 46,
1824
+
XRT_FACE_PARAMETER_INDICES_LIP_SUCK_RT_ANDROID = 47,
1825
+
XRT_FACE_PARAMETER_INDICES_LIP_TIGHTENER_L_ANDROID = 48,
1826
+
XRT_FACE_PARAMETER_INDICES_LIP_TIGHTENER_R_ANDROID = 49,
1827
+
XRT_FACE_PARAMETER_INDICES_LIPS_TOWARD_ANDROID = 50,
1828
+
XRT_FACE_PARAMETER_INDICES_LOWER_LIP_DEPRESSOR_L_ANDROID = 51,
1829
+
XRT_FACE_PARAMETER_INDICES_LOWER_LIP_DEPRESSOR_R_ANDROID = 52,
1830
+
XRT_FACE_PARAMETER_INDICES_MOUTH_LEFT_ANDROID = 53,
1831
+
XRT_FACE_PARAMETER_INDICES_MOUTH_RIGHT_ANDROID = 54,
1832
+
XRT_FACE_PARAMETER_INDICES_NOSE_WRINKLER_L_ANDROID = 55,
1833
+
XRT_FACE_PARAMETER_INDICES_NOSE_WRINKLER_R_ANDROID = 56,
1834
+
XRT_FACE_PARAMETER_INDICES_OUTER_BROW_RAISER_L_ANDROID = 57,
1835
+
XRT_FACE_PARAMETER_INDICES_OUTER_BROW_RAISER_R_ANDROID = 58,
1836
+
XRT_FACE_PARAMETER_INDICES_UPPER_LID_RAISER_L_ANDROID = 59,
1837
+
XRT_FACE_PARAMETER_INDICES_UPPER_LID_RAISER_R_ANDROID = 60,
1838
+
XRT_FACE_PARAMETER_INDICES_UPPER_LIP_RAISER_L_ANDROID = 61,
1839
+
XRT_FACE_PARAMETER_INDICES_UPPER_LIP_RAISER_R_ANDROID = 62,
1840
+
XRT_FACE_PARAMETER_INDICES_TONGUE_OUT_ANDROID = 63,
1841
+
XRT_FACE_PARAMETER_INDICES_TONGUE_LEFT_ANDROID = 64,
1842
+
XRT_FACE_PARAMETER_INDICES_TONGUE_RIGHT_ANDROID = 65,
1843
+
XRT_FACE_PARAMETER_INDICES_TONGUE_UP_ANDROID = 66,
1844
+
XRT_FACE_PARAMETER_INDICES_TONGUE_DOWN_ANDROID = 67,
1845
+
};
1846
+
1847
+
enum xrt_face_tracking_state_android
1848
+
{
1849
+
XRT_FACE_TRACKING_STATE_PAUSED_ANDROID = 0,
1850
+
XRT_FACE_TRACKING_STATE_STOPPED_ANDROID = 1,
1851
+
XRT_FACE_TRACKING_STATE_TRACKING_ANDROID = 2,
1852
+
};
1853
+
1854
+
#define XRT_FACE_PARAMETER_COUNT_ANDROID 68
1855
+
1856
+
#define XRT_FACE_REGION_CONFIDENCE_COUNT_ANDROID 3
1857
+
1858
struct xrt_facial_base_expression_set_htc
1859
{
1860
int64_t sample_time_ns;
···
1887
bool is_eye_following_blendshapes_valid;
1888
};
1889
1890
+
struct xrt_facial_expression_set_android
1891
+
{
1892
+
// ordered by xrt_face_parameter_indices_android
1893
+
float parameters[XRT_FACE_PARAMETER_COUNT_ANDROID];
1894
+
float region_confidences[XRT_FACE_REGION_CONFIDENCE_COUNT_ANDROID];
1895
+
1896
+
uint64_t sample_time_ns;
1897
+
1898
+
XRT_ALIGNAS(8) bool is_valid;
1899
+
};
1900
+
1901
struct xrt_facial_expression_set
1902
{
1903
union {
···
1905
struct xrt_facial_eye_expression_set_htc eye_expression_set_htc;
1906
struct xrt_facial_lip_expression_set_htc lip_expression_set_htc;
1907
struct xrt_facial_expression_set2_fb face_expression_set2_fb;
1908
+
struct xrt_facial_expression_set_android face_expression_set_android;
1909
};
1910
};
1911
···
2176
};
2177
2178
/*!
2179
* Value used to indicate a haptic pulse of the minimal supported duration.
2180
*
2181
* @ingroup xrt_iface
···
2274
{
2275
XRT_FORM_FACTOR_HMD, //!< Head mounted display.
2276
XRT_FORM_FACTOR_HANDHELD, //!< Handheld display.
2277
+
};
2278
+
2279
+
/*!
2280
+
* View type to be rendered to by the compositor.
2281
+
*/
2282
+
enum xrt_view_type
2283
+
{
2284
+
XRT_VIEW_TYPE_MONO = 1,
2285
+
XRT_VIEW_TYPE_STEREO = 2,
2286
};
2287
2288
/*!
+55
-22
src/xrt/include/xrt/xrt_device.h
+55
-22
src/xrt/include/xrt/xrt_device.h
···
103
//! Nominal frame interval
104
uint64_t nominal_frame_interval_ns;
105
enum xrt_scanout_direction scanout_direction;
106
-
uint64_t scanout_time_ns;
107
} screens[1];
108
109
/*!
···
406
struct xrt_facial_expression_set *out_value);
407
408
/*!
409
* @brief Get the body skeleton in T-pose, used to query the skeleton hierarchy, scale, proportions etc
410
*
411
* @param[in] xdev The device.
···
489
* @param[out] out_plane_detection_id The id of the new plane detection request generated by the xdev.
490
* @return generally XRT_SUCCESS, except for internal runtime failures.
491
*/
492
-
enum xrt_result (*begin_plane_detection_ext)(struct xrt_device *xdev,
493
-
const struct xrt_plane_detector_begin_info_ext *begin_info,
494
-
uint64_t plane_detection_id,
495
-
uint64_t *out_plane_detection_id);
496
497
/*!
498
* Destroy internal resources associated with plane_detector_id.
···
501
* @param[in] plane_detection_id An id generated by the xdev.
502
* @return generally XRT_SUCCESS, except for internal runtime failures.
503
*/
504
-
enum xrt_result (*destroy_plane_detection_ext)(struct xrt_device *xdev, uint64_t plane_detection_id);
505
506
/*!
507
* Get the state of a plane detection request.
···
511
* @param[out] out_state The state of the plane detection.
512
* @return generally XRT_SUCCESS, except for internal runtime failures.
513
*/
514
-
enum xrt_result (*get_plane_detection_state_ext)(struct xrt_device *xdev,
515
-
uint64_t plane_detection_id,
516
-
enum xrt_plane_detector_state_ext *out_state);
517
518
/*!
519
* Get results of a plane detection request.
···
523
* @param[out] detections The detected planes, if any.
524
* @return generally XRT_SUCCESS, except for internal runtime failures.
525
*/
526
-
enum xrt_result (*get_plane_detections_ext)(struct xrt_device *xdev,
527
-
uint64_t plane_detection_id,
528
-
struct xrt_plane_detections_ext *out_detections);
529
530
/*!
531
* @brief Get the per-view pose in relation to the view space.
···
550
* input.
551
* @param[in] at_timestamp_ns This is when the caller wants the poses and FOVs to be from.
552
* @param[in] view_count Number of views.
553
* @param[out] out_head_relation
554
* The head pose in the device tracking space.
555
* Combine with @p out_poses to get the views in
···
567
xrt_result_t (*get_view_poses)(struct xrt_device *xdev,
568
const struct xrt_vec3 *default_eye_relation,
569
int64_t at_timestamp_ns,
570
uint32_t view_count,
571
struct xrt_space_relation *out_head_relation,
572
struct xrt_fov *out_fovs,
···
754
}
755
756
/*!
757
* Helper function for @ref xrt_device::get_body_skeleton.
758
*
759
* @copydoc xrt_device::get_body_skeleton
···
858
}
859
860
/*!
861
-
* Helper function for @ref xrt_device::begin_plane_detection.
862
*
863
* @public @memberof xrt_device
864
*/
865
-
static inline enum xrt_result
866
xrt_device_begin_plane_detection_ext(struct xrt_device *xdev,
867
const struct xrt_plane_detector_begin_info_ext *begin_info,
868
uint64_t plane_detection_id,
···
872
}
873
874
/*!
875
-
* Helper function for @ref xrt_device::destroy_plane_detection.
876
*
877
* @public @memberof xrt_device
878
*/
879
-
static inline enum xrt_result
880
xrt_device_destroy_plane_detection_ext(struct xrt_device *xdev, uint64_t plane_detection_id)
881
{
882
return xdev->destroy_plane_detection_ext(xdev, plane_detection_id);
883
}
884
885
/*!
886
-
* Helper function for @ref xrt_device::get_plane_detections.
887
*
888
* @public @memberof xrt_device
889
*/
890
-
static inline enum xrt_result
891
xrt_device_get_plane_detection_state_ext(struct xrt_device *xdev,
892
uint64_t plane_detection_id,
893
enum xrt_plane_detector_state_ext *out_state)
···
896
}
897
898
/*!
899
-
* Helper function for @ref xrt_device::get_plane_detections.
900
*
901
* @public @memberof xrt_device
902
*/
903
-
static inline enum xrt_result
904
xrt_device_get_plane_detections_ext(struct xrt_device *xdev,
905
uint64_t plane_detection_id,
906
struct xrt_plane_detections_ext *out_detections)
···
918
xrt_device_get_view_poses(struct xrt_device *xdev,
919
const struct xrt_vec3 *default_eye_relation,
920
int64_t at_timestamp_ns,
921
uint32_t view_count,
922
struct xrt_space_relation *out_head_relation,
923
struct xrt_fov *out_fovs,
924
struct xrt_pose *out_poses)
925
{
926
-
return xdev->get_view_poses(xdev, default_eye_relation, at_timestamp_ns, view_count, out_head_relation,
927
-
out_fovs, out_poses);
928
}
929
930
/*!
···
103
//! Nominal frame interval
104
uint64_t nominal_frame_interval_ns;
105
enum xrt_scanout_direction scanout_direction;
106
+
int64_t scanout_time_ns;
107
} screens[1];
108
109
/*!
···
406
struct xrt_facial_expression_set *out_value);
407
408
/*!
409
+
* @brief Gets the face tracking calibration state
410
+
*
411
+
* @param[in] xdev The device.
412
+
* @param[in] out_value Is face tracking calibrated?
413
+
*
414
+
* @see xrt_input_name
415
+
*/
416
+
xrt_result_t (*get_face_calibration_state_android)(struct xrt_device *xdev, bool *out_face_is_calibrated);
417
+
418
+
/*!
419
* @brief Get the body skeleton in T-pose, used to query the skeleton hierarchy, scale, proportions etc
420
*
421
* @param[in] xdev The device.
···
499
* @param[out] out_plane_detection_id The id of the new plane detection request generated by the xdev.
500
* @return generally XRT_SUCCESS, except for internal runtime failures.
501
*/
502
+
xrt_result_t (*begin_plane_detection_ext)(struct xrt_device *xdev,
503
+
const struct xrt_plane_detector_begin_info_ext *begin_info,
504
+
uint64_t plane_detection_id,
505
+
uint64_t *out_plane_detection_id);
506
507
/*!
508
* Destroy internal resources associated with plane_detector_id.
···
511
* @param[in] plane_detection_id An id generated by the xdev.
512
* @return generally XRT_SUCCESS, except for internal runtime failures.
513
*/
514
+
xrt_result_t (*destroy_plane_detection_ext)(struct xrt_device *xdev, uint64_t plane_detection_id);
515
516
/*!
517
* Get the state of a plane detection request.
···
521
* @param[out] out_state The state of the plane detection.
522
* @return generally XRT_SUCCESS, except for internal runtime failures.
523
*/
524
+
xrt_result_t (*get_plane_detection_state_ext)(struct xrt_device *xdev,
525
+
uint64_t plane_detection_id,
526
+
enum xrt_plane_detector_state_ext *out_state);
527
528
/*!
529
* Get results of a plane detection request.
···
533
* @param[out] detections The detected planes, if any.
534
* @return generally XRT_SUCCESS, except for internal runtime failures.
535
*/
536
+
xrt_result_t (*get_plane_detections_ext)(struct xrt_device *xdev,
537
+
uint64_t plane_detection_id,
538
+
struct xrt_plane_detections_ext *out_detections);
539
540
/*!
541
* @brief Get the per-view pose in relation to the view space.
···
560
* input.
561
* @param[in] at_timestamp_ns This is when the caller wants the poses and FOVs to be from.
562
* @param[in] view_count Number of views.
563
+
* @param[in] view_type Type of view configuration (mono or stereo).
564
* @param[out] out_head_relation
565
* The head pose in the device tracking space.
566
* Combine with @p out_poses to get the views in
···
578
xrt_result_t (*get_view_poses)(struct xrt_device *xdev,
579
const struct xrt_vec3 *default_eye_relation,
580
int64_t at_timestamp_ns,
581
+
enum xrt_view_type view_type,
582
uint32_t view_count,
583
struct xrt_space_relation *out_head_relation,
584
struct xrt_fov *out_fovs,
···
766
}
767
768
/*!
769
+
* Helper function for @ref xrt_device::get_face_calibration_state_android.
770
+
*
771
+
* @copydoc xrt_device::get_face_calibration_state_android
772
+
*
773
+
* @public @memberof xrt_device
774
+
*/
775
+
static inline xrt_result_t
776
+
xrt_device_get_face_calibration_state_android(struct xrt_device *xdev, bool *out_face_is_calibrated)
777
+
{
778
+
return xdev->get_face_calibration_state_android(xdev, out_face_is_calibrated);
779
+
}
780
+
781
+
/*!
782
* Helper function for @ref xrt_device::get_body_skeleton.
783
*
784
* @copydoc xrt_device::get_body_skeleton
···
883
}
884
885
/*!
886
+
* Helper function for @ref xrt_device::begin_plane_detection_ext.
887
*
888
* @public @memberof xrt_device
889
*/
890
+
static inline xrt_result_t
891
xrt_device_begin_plane_detection_ext(struct xrt_device *xdev,
892
const struct xrt_plane_detector_begin_info_ext *begin_info,
893
uint64_t plane_detection_id,
···
897
}
898
899
/*!
900
+
* Helper function for @ref xrt_device::destroy_plane_detection_ext.
901
*
902
* @public @memberof xrt_device
903
*/
904
+
static inline xrt_result_t
905
xrt_device_destroy_plane_detection_ext(struct xrt_device *xdev, uint64_t plane_detection_id)
906
{
907
return xdev->destroy_plane_detection_ext(xdev, plane_detection_id);
908
}
909
910
/*!
911
+
* Helper function for @ref xrt_device::get_plane_detections_ext.
912
*
913
* @public @memberof xrt_device
914
*/
915
+
static inline xrt_result_t
916
xrt_device_get_plane_detection_state_ext(struct xrt_device *xdev,
917
uint64_t plane_detection_id,
918
enum xrt_plane_detector_state_ext *out_state)
···
921
}
922
923
/*!
924
+
* Helper function for @ref xrt_device::get_plane_detections_ext.
925
*
926
* @public @memberof xrt_device
927
*/
928
+
static inline xrt_result_t
929
xrt_device_get_plane_detections_ext(struct xrt_device *xdev,
930
uint64_t plane_detection_id,
931
struct xrt_plane_detections_ext *out_detections)
···
943
xrt_device_get_view_poses(struct xrt_device *xdev,
944
const struct xrt_vec3 *default_eye_relation,
945
int64_t at_timestamp_ns,
946
+
enum xrt_view_type view_type,
947
uint32_t view_count,
948
struct xrt_space_relation *out_head_relation,
949
struct xrt_fov *out_fovs,
950
struct xrt_pose *out_poses)
951
{
952
+
return xdev->get_view_poses( //
953
+
xdev, //
954
+
default_eye_relation, //
955
+
at_timestamp_ns, //
956
+
view_type, //
957
+
view_count, //
958
+
out_head_relation, //
959
+
out_fovs, //
960
+
out_poses); //
961
}
962
963
/*!
+21
src/xrt/include/xrt/xrt_instance.h
+21
src/xrt/include/xrt/xrt_instance.h
···
1
// Copyright 2020-2024, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
81
bool fb_face_tracking2_enabled;
82
bool meta_body_tracking_full_body_enabled;
83
bool meta_body_tracking_calibration_enabled;
84
};
85
86
/*!
···
126
*/
127
128
/*!
129
* Creates all of the system resources like the devices and system
130
* compositor. The system compositor is optional.
131
*
···
198
*/
199
struct xrt_instance_android *android_instance;
200
};
201
202
/*!
203
* @copydoc xrt_instance::create_system
···
1
// Copyright 2020-2024, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
82
bool fb_face_tracking2_enabled;
83
bool meta_body_tracking_full_body_enabled;
84
bool meta_body_tracking_calibration_enabled;
85
+
bool android_face_tracking_enabled;
86
};
87
88
/*!
···
128
*/
129
130
/*!
131
+
* Checks if the system can be created with create_system().
132
+
*/
133
+
xrt_result_t (*is_system_available)(struct xrt_instance *xinst, bool *out_available);
134
+
135
+
/*!
136
* Creates all of the system resources like the devices and system
137
* compositor. The system compositor is optional.
138
*
···
205
*/
206
struct xrt_instance_android *android_instance;
207
};
208
+
209
+
210
+
/*!
211
+
* @copydoc xrt_instance::create_system
212
+
*
213
+
* Helper for calling through the function pointer.
214
+
*
215
+
* @public @memberof xrt_instance
216
+
*/
217
+
static inline xrt_result_t
218
+
xrt_instance_is_system_available(struct xrt_instance *xinst, bool *out_available)
219
+
{
220
+
return xinst->is_system_available(xinst, out_available);
221
+
}
222
223
/*!
224
* @copydoc xrt_instance::create_system
+18
src/xrt/include/xrt/xrt_limits.h
+18
src/xrt/include/xrt/xrt_limits.h
···
1
// Copyright 2019-2022, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
9
10
#pragma once
11
12
#include "xrt/xrt_compiler.h"
13
14
···
20
* Max number of views supported by a compositor, artificial limit.
21
*/
22
#define XRT_MAX_VIEWS 2
23
24
/*!
25
* Maximum number of handles sent in one call.
···
61
/*!
62
* Max number of layers which can be handled at once.
63
*/
64
#define XRT_MAX_LAYERS 128
65
66
/*!
67
* @}
···
1
// Copyright 2019-2022, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
10
11
#pragma once
12
13
+
#include "xrt/xrt_config_os.h"
14
#include "xrt/xrt_compiler.h"
15
16
···
22
* Max number of views supported by a compositor, artificial limit.
23
*/
24
#define XRT_MAX_VIEWS 2
25
+
26
+
/*
27
+
* System needs to support at least 4 views for stereo with foveated inset.
28
+
*/
29
+
#define XRT_MAX_COMPOSITOR_VIEW_CONFIGS_VIEW_COUNT (XRT_MAX_VIEWS > 4 ? XRT_MAX_VIEWS : 4)
30
+
31
+
/*
32
+
* Max number of view configurations a system compositor can support simultaneously.
33
+
*/
34
+
#define XRT_MAX_COMPOSITOR_VIEW_CONFIGS_COUNT 2
35
36
/*!
37
* Maximum number of handles sent in one call.
···
73
/*!
74
* Max number of layers which can be handled at once.
75
*/
76
+
#ifdef XRT_OS_ANDROID
77
+
#define XRT_MAX_LAYERS 32
78
+
#elif defined(XRT_OS_LINUX) || defined(XRT_OS_WINDOWS)
79
#define XRT_MAX_LAYERS 128
80
+
#else
81
+
#error "Unknown platform, define XRT_MAX_LAYERS for your OS"
82
+
#endif
83
84
/*!
85
* @}
+6
src/xrt/include/xrt/xrt_results.h
+6
src/xrt/include/xrt/xrt_results.h
+1
src/xrt/include/xrt/xrt_session.h
+1
src/xrt/include/xrt/xrt_session.h
+80
src/xrt/include/xrt/xrt_space.h
+80
src/xrt/include/xrt/xrt_space.h
···
1
// Copyright 2019-2023, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
303
struct xrt_space **out_local_space,
304
struct xrt_space **out_local_floor_space);
305
306
/*!
307
* Destroy function.
308
*
···
513
struct xrt_space **out_local_floor_space)
514
{
515
return xso->create_local_space(xso, out_local_space, out_local_floor_space);
516
}
517
518
/*!
···
1
// Copyright 2019-2023, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
304
struct xrt_space **out_local_space,
305
struct xrt_space **out_local_floor_space);
306
307
+
/*
308
+
*
309
+
* Special inter-monado component functions.
310
+
*
311
+
*/
312
+
313
+
/*!
314
+
* Add a new device to be tracked by the space overseer. The exact
315
+
* semantic of the space is determined by the implementation of the
316
+
* space overseer. And may be outright rejected by the implementation.
317
+
*
318
+
* After this call completes successfully, the device can be passed
319
+
* into the @ref xrt_space_overseer::locate_device function, but may
320
+
* not be locatable immediately.
321
+
*
322
+
* This function is not intended to be called by the OpenXR state
323
+
* tracker, but by other monado components that need to add devices
324
+
* but does not own the space overseer. Components like the fixer
325
+
* uppers or for push devices.
326
+
*
327
+
* @param[in] xso The space overseer.
328
+
* @param[in] xdev The device to be tracked.
329
+
* @return XRT_SUCCESS if added, otherwise an error code.
330
+
*/
331
+
xrt_result_t (*add_device)(struct xrt_space_overseer *xso, struct xrt_device *xdev);
332
+
333
+
/*!
334
+
* Attach a device to a different space then it was associated with
335
+
* originally, the space overseer might not support this operation.
336
+
*
337
+
* For some space overseer implementations this operation requires
338
+
* that the device has the tracking origin type of
339
+
* @ref XRT_TRACKING_TYPE_ATTACHABLE. Which space that becomes the
340
+
* parent space of the device when @p space is NULL is undefined,
341
+
* and the device might become un-trackable.
342
+
*
343
+
* @param[in] xso Owning space overseer.
344
+
* @param[in] xdev Device to attach.
345
+
* @param[in] space Space to attach the device to, may be NULL.
346
+
*
347
+
* @return XRT_SUCCESS on success.
348
+
* @return XRT_ERROR_DEVICE_NOT_ATTACHABLE if the device does not have
349
+
* the XRT_TRACKING_TYPE_ATTACHABLE tracking origin type.
350
+
*/
351
+
xrt_result_t (*attach_device)(struct xrt_space_overseer *xso, struct xrt_device *xdev, struct xrt_space *space);
352
+
353
+
354
+
/*
355
+
*
356
+
* Destroy function always comes last.
357
+
*
358
+
*/
359
+
360
/*!
361
* Destroy function.
362
*
···
567
struct xrt_space **out_local_floor_space)
568
{
569
return xso->create_local_space(xso, out_local_space, out_local_floor_space);
570
+
}
571
+
572
+
/*!
573
+
* @copydoc xrt_space_overseer::add_device
574
+
*
575
+
* Helper for calling through the function pointer.
576
+
*
577
+
* @public @memberof xrt_space_overseer
578
+
*/
579
+
static inline xrt_result_t
580
+
xrt_space_overseer_add_device(struct xrt_space_overseer *xso, struct xrt_device *xdev)
581
+
{
582
+
return xso->add_device(xso, xdev);
583
+
}
584
+
585
+
/*!
586
+
* @copydoc xrt_space_overseer::attach_device
587
+
*
588
+
* Helper for calling through the function pointer.
589
+
*
590
+
* @public @memberof xrt_space_overseer
591
+
*/
592
+
static inline xrt_result_t
593
+
xrt_space_overseer_attach_device(struct xrt_space_overseer *xso, struct xrt_device *xdev, struct xrt_space *space)
594
+
{
595
+
return xso->attach_device(xso, xdev, space);
596
}
597
598
/*!
+4
src/xrt/include/xrt/xrt_tracking.h
+4
src/xrt/include/xrt/xrt_tracking.h
···
1
// Copyright 2019, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
61
62
// The device(s) are tracked by other methods.
63
XRT_TRACKING_TYPE_OTHER,
64
+
65
+
// The device(s) are (re)attachable.
66
+
XRT_TRACKING_TYPE_ATTACHABLE,
67
};
68
69
/*!
+32
-3
src/xrt/ipc/CMakeLists.txt
+32
-3
src/xrt/ipc/CMakeLists.txt
···
1
# Copyright 2020-2021, Collabora, Ltd.
2
# SPDX-License-Identifier: BSL-1.0
3
4
###
5
# Generator
6
7
foreach(
···
16
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${fn}"
17
COMMAND
18
${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/shared/proto.py
19
-
${CMAKE_CURRENT_SOURCE_DIR}/shared/proto.json
20
-
"${CMAKE_CURRENT_BINARY_DIR}/${fn}"
21
VERBATIM
22
DEPENDS
23
${CMAKE_CURRENT_SOURCE_DIR}/shared/proto.py
24
${CMAKE_CURRENT_SOURCE_DIR}/shared/ipcproto/common.py
25
-
${CMAKE_CURRENT_SOURCE_DIR}/shared/proto.json
26
COMMENT "Generating ${fn} from protocol JSON description"
27
)
28
endforeach()
29
30
set(IPC_COMMON_SOURCES
31
${CMAKE_CURRENT_BINARY_DIR}/ipc_protocol_generated.h
···
1
# Copyright 2020-2021, Collabora, Ltd.
2
+
# Copyright 2025, NVIDIA CORPORATION.
3
# SPDX-License-Identifier: BSL-1.0
4
5
###
6
+
# Merge split protocol JSON files into single proto.json
7
+
file(GLOB PROTO_JSON_FILES "${CMAKE_CURRENT_SOURCE_DIR}/shared/proto/*.json")
8
+
9
+
merge_json_files(
10
+
OUTPUT
11
+
"${CMAKE_CURRENT_BINARY_DIR}/proto.json"
12
+
SOURCES
13
+
${PROTO_JSON_FILES}
14
+
IGNORE_SCHEMA
15
+
)
16
+
17
+
###
18
# Generator
19
20
foreach(
···
29
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${fn}"
30
COMMAND
31
${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/shared/proto.py
32
+
${CMAKE_CURRENT_BINARY_DIR}/proto.json "${CMAKE_CURRENT_BINARY_DIR}/${fn}"
33
VERBATIM
34
DEPENDS
35
${CMAKE_CURRENT_SOURCE_DIR}/shared/proto.py
36
${CMAKE_CURRENT_SOURCE_DIR}/shared/ipcproto/common.py
37
+
${CMAKE_CURRENT_BINARY_DIR}/proto.json
38
+
${CMAKE_CURRENT_SOURCE_DIR}/shared/ipc_protocol_generated.h.template
39
COMMENT "Generating ${fn} from protocol JSON description"
40
)
41
endforeach()
42
+
43
+
# Generate IPC structures list in the build root
44
+
add_custom_command(
45
+
OUTPUT "${CMAKE_BINARY_DIR}/ipc-structs.txt"
46
+
COMMAND
47
+
${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/shared/proto.py
48
+
${CMAKE_CURRENT_BINARY_DIR}/proto.json "${CMAKE_BINARY_DIR}/ipc-structs.txt"
49
+
VERBATIM
50
+
DEPENDS
51
+
${CMAKE_CURRENT_SOURCE_DIR}/shared/proto.py
52
+
${CMAKE_CURRENT_SOURCE_DIR}/shared/ipcproto/common.py
53
+
${CMAKE_CURRENT_BINARY_DIR}/proto.json
54
+
COMMENT "Generating ipc-structs.txt from protocol JSON description"
55
+
)
56
+
57
+
add_custom_target(ipc_structs_list ALL DEPENDS "${CMAKE_BINARY_DIR}/ipc-structs.txt")
58
59
set(IPC_COMMON_SOURCES
60
${CMAKE_CURRENT_BINARY_DIR}/ipc_protocol_generated.h
+24
-1
src/xrt/ipc/client/ipc_client.h
+24
-1
src/xrt/ipc/client/ipc_client.h
···
1
// Copyright 2020-2023, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
16
17
#include "util/u_threading.h"
18
#include "util/u_logging.h"
19
20
#include "shared/ipc_utils.h"
21
#include "shared/ipc_protocol.h"
···
69
#endif // XRT_OS_ANDROID
70
};
71
72
73
/*
74
*
···
125
struct xrt_space_overseer *
126
ipc_client_space_overseer_create(struct ipc_connection *ipc_c);
127
128
-
struct xrt_system_devices *
129
ipc_client_system_devices_create(struct ipc_connection *ipc_c);
130
131
struct xrt_session *
···
1
// Copyright 2020-2023, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
17
18
#include "util/u_threading.h"
19
#include "util/u_logging.h"
20
+
#include "util/u_system_helpers.h"
21
22
#include "shared/ipc_utils.h"
23
#include "shared/ipc_protocol.h"
···
71
#endif // XRT_OS_ANDROID
72
};
73
74
+
/*!
75
+
* Client side implementation of the system devices struct.
76
+
*/
77
+
struct ipc_client_system_devices
78
+
{
79
+
//! @public Base
80
+
struct u_system_devices base;
81
+
82
+
//! Connection to service.
83
+
struct ipc_connection *ipc_c;
84
+
85
+
struct xrt_tracking_origin *xtracks[XRT_SYSTEM_MAX_DEVICES];
86
+
87
+
size_t xtrack_count;
88
+
89
+
struct xrt_reference feature_use[XRT_DEVICE_FEATURE_MAX_ENUM];
90
+
};
91
+
92
93
/*
94
*
···
145
struct xrt_space_overseer *
146
ipc_client_space_overseer_create(struct ipc_connection *ipc_c);
147
148
+
uint32_t
149
+
ipc_client_space_get_id(struct xrt_space *space);
150
+
151
+
struct ipc_client_system_devices *
152
ipc_client_system_devices_create(struct ipc_connection *ipc_c);
153
154
struct xrt_session *
+12
-1
src/xrt/ipc/client/ipc_client_compositor.c
+12
-1
src/xrt/ipc/client/ipc_client_compositor.c
···
1
// Copyright 2020, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
288
&use_dedicated_allocation, // out
289
remote_handles, // handles
290
XRT_MAX_SWAPCHAIN_IMAGES); // handles
291
IPC_CHK_AND_RET(icc->ipc_c, xret, "ipc_call_swapchain_create");
292
293
struct ipc_client_swapchain *ics = U_TYPED_CALLOC(struct ipc_client_swapchain);
···
345
handles, // handles
346
image_count, // handles
347
&id); // out
348
-
IPC_CHK_AND_RET(icc->ipc_c, xret, "ipc_call_swapchain_create");
349
350
struct ipc_client_swapchain *ics = U_TYPED_CALLOC(struct ipc_client_swapchain);
351
ics->base.base.image_count = image_count;
···
1
// Copyright 2020, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
289
&use_dedicated_allocation, // out
290
remote_handles, // handles
291
XRT_MAX_SWAPCHAIN_IMAGES); // handles
292
+
if (xret == XRT_ERROR_SWAPCHAIN_FLAG_VALID_BUT_UNSUPPORTED) {
293
+
// Don't error print this, will spam CTS logs.
294
+
IPC_DEBUG(icc->ipc_c, "Got XRT_ERROR_SWAPCHAIN_FLAG_VALID_BUT_UNSUPPORTED");
295
+
return xret;
296
+
}
297
IPC_CHK_AND_RET(icc->ipc_c, xret, "ipc_call_swapchain_create");
298
299
struct ipc_client_swapchain *ics = U_TYPED_CALLOC(struct ipc_client_swapchain);
···
351
handles, // handles
352
image_count, // handles
353
&id); // out
354
+
if (xret == XRT_ERROR_SWAPCHAIN_FLAG_VALID_BUT_UNSUPPORTED) {
355
+
// Don't error print this, not an error.
356
+
IPC_DEBUG(icc->ipc_c, "Got XRT_ERROR_SWAPCHAIN_FLAG_VALID_BUT_UNSUPPORTED");
357
+
return xret;
358
+
}
359
+
IPC_CHK_AND_RET(icc->ipc_c, xret, "ipc_call_swapchain_import");
360
361
struct ipc_client_swapchain *ics = U_TYPED_CALLOC(struct ipc_client_swapchain);
362
ics->base.base.image_count = image_count;
+1
-4
src/xrt/ipc/client/ipc_client_device.c
+1
-4
src/xrt/ipc/client/ipc_client_device.c
···
86
ipc_client_device_t *icd = U_DEVICE_ALLOCATE(ipc_client_device_t, flags, 0, 0);
87
88
// Fills in almost everything a regular device needs.
89
-
ipc_client_xdev_init(icd, ipc_c, xtrack, device_id);
90
-
91
-
// Need to set the destroy function.
92
-
icd->base.destroy = ipc_client_device_destroy;
93
94
// Setup variable tracker.
95
u_var_add_root(icd, icd->base.str, true);
···
86
ipc_client_device_t *icd = U_DEVICE_ALLOCATE(ipc_client_device_t, flags, 0, 0);
87
88
// Fills in almost everything a regular device needs.
89
+
ipc_client_xdev_init(icd, ipc_c, xtrack, device_id, ipc_client_device_destroy);
90
91
// Setup variable tracker.
92
u_var_add_root(icd, icd->base.str, true);
+6
-2
src/xrt/ipc/client/ipc_client_hmd.c
+6
-2
src/xrt/ipc/client/ipc_client_hmd.c
···
66
call_get_view_poses_raw(ipc_client_hmd_t *ich,
67
const struct xrt_vec3 *default_eye_relation,
68
int64_t at_timestamp_ns,
69
uint32_t view_count,
70
struct xrt_space_relation *out_head_relation,
71
struct xrt_fov *out_fovs,
···
82
ich->device_id, //
83
default_eye_relation, //
84
at_timestamp_ns, //
85
view_count); //
86
IPC_CHK_WITH_GOTO(ich->ipc_c, xret, "ipc_send_device_get_view_poses_locked", out);
87
···
131
ipc_client_hmd_get_view_poses(struct xrt_device *xdev,
132
const struct xrt_vec3 *default_eye_relation,
133
int64_t at_timestamp_ns,
134
uint32_t view_count,
135
struct xrt_space_relation *out_head_relation,
136
struct xrt_fov *out_fovs,
···
148
ich->device_id, //
149
default_eye_relation, //
150
at_timestamp_ns, //
151
view_count, //
152
&info); //
153
IPC_CHK_AND_RET(ich->ipc_c, xret, "ipc_call_device_get_view_poses_2");
···
164
ich, //
165
default_eye_relation, //
166
at_timestamp_ns, //
167
view_count, //
168
out_head_relation, //
169
out_fovs, //
···
316
ipc_client_hmd_t *ich = U_DEVICE_ALLOCATE(ipc_client_hmd_t, flags, 0, 0);
317
318
// Fills in almost everything a regular device needs.
319
-
ipc_client_xdev_init(ich, ipc_c, xtrack, device_id);
320
321
// Fill in needed HMD functions, and destroy.
322
ich->base.get_view_poses = ipc_client_hmd_get_view_poses;
323
ich->base.compute_distortion = ipc_client_hmd_compute_distortion;
324
ich->base.is_form_factor_available = ipc_client_hmd_is_form_factor_available;
325
ich->base.get_visibility_mask = ipc_client_hmd_get_visibility_mask;
326
-
ich->base.destroy = ipc_client_hmd_destroy;
327
ich->base.get_brightness = ipc_client_hmd_get_brightness;
328
ich->base.set_brightness = ipc_client_hmd_set_brightness;
329
···
66
call_get_view_poses_raw(ipc_client_hmd_t *ich,
67
const struct xrt_vec3 *default_eye_relation,
68
int64_t at_timestamp_ns,
69
+
enum xrt_view_type view_type,
70
uint32_t view_count,
71
struct xrt_space_relation *out_head_relation,
72
struct xrt_fov *out_fovs,
···
83
ich->device_id, //
84
default_eye_relation, //
85
at_timestamp_ns, //
86
+
view_type, //
87
view_count); //
88
IPC_CHK_WITH_GOTO(ich->ipc_c, xret, "ipc_send_device_get_view_poses_locked", out);
89
···
133
ipc_client_hmd_get_view_poses(struct xrt_device *xdev,
134
const struct xrt_vec3 *default_eye_relation,
135
int64_t at_timestamp_ns,
136
+
enum xrt_view_type view_type,
137
uint32_t view_count,
138
struct xrt_space_relation *out_head_relation,
139
struct xrt_fov *out_fovs,
···
151
ich->device_id, //
152
default_eye_relation, //
153
at_timestamp_ns, //
154
+
view_type, //
155
view_count, //
156
&info); //
157
IPC_CHK_AND_RET(ich->ipc_c, xret, "ipc_call_device_get_view_poses_2");
···
168
ich, //
169
default_eye_relation, //
170
at_timestamp_ns, //
171
+
view_type, //
172
view_count, //
173
out_head_relation, //
174
out_fovs, //
···
321
ipc_client_hmd_t *ich = U_DEVICE_ALLOCATE(ipc_client_hmd_t, flags, 0, 0);
322
323
// Fills in almost everything a regular device needs.
324
+
ipc_client_xdev_init(ich, ipc_c, xtrack, device_id, ipc_client_hmd_destroy);
325
326
// Fill in needed HMD functions, and destroy.
327
ich->base.get_view_poses = ipc_client_hmd_get_view_poses;
328
ich->base.compute_distortion = ipc_client_hmd_compute_distortion;
329
ich->base.is_form_factor_available = ipc_client_hmd_is_form_factor_available;
330
ich->base.get_visibility_mask = ipc_client_hmd_get_visibility_mask;
331
ich->base.get_brightness = ipc_client_hmd_get_brightness;
332
ich->base.set_brightness = ipc_client_hmd_set_brightness;
333
+45
-58
src/xrt/ipc/client/ipc_client_instance.c
+45
-58
src/xrt/ipc/client/ipc_client_instance.c
···
1
// Copyright 2020-2024, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
78
79
struct ipc_connection ipc_c;
80
81
-
struct xrt_tracking_origin *xtracks[XRT_SYSTEM_MAX_DEVICES];
82
-
size_t xtrack_count;
83
-
84
-
struct xrt_device *xdevs[XRT_SYSTEM_MAX_DEVICES];
85
-
size_t xdev_count;
86
-
87
#ifdef XRT_OS_ANDROID
88
struct android_instance_base android;
89
#endif
···
136
*/
137
138
static xrt_result_t
139
ipc_client_instance_create_system(struct xrt_instance *xinst,
140
struct xrt_system **out_xsys,
141
struct xrt_system_devices **out_xsysd,
···
151
assert(*out_xsysd == NULL);
152
assert(out_xsysc == NULL || *out_xsysc == NULL);
153
154
-
struct xrt_system_devices *xsysd = NULL;
155
struct xrt_system_compositor *xsysc = NULL;
156
157
// Allocate a helper xrt_system_devices struct.
158
-
xsysd = ipc_client_system_devices_create(&ii->ipc_c);
159
160
-
// Take the devices from this instance.
161
-
for (uint32_t i = 0; i < ii->xdev_count; i++) {
162
-
xsysd->xdevs[i] = ii->xdevs[i];
163
-
ii->xdevs[i] = NULL;
164
}
165
-
xsysd->xdev_count = ii->xdev_count;
166
-
ii->xdev_count = 0;
167
168
#define SET_ROLE(ROLE) \
169
do { \
···
231
232
// service considers us to be connected until fd is closed
233
ipc_client_connection_fini(&ii->ipc_c);
234
-
235
-
for (size_t i = 0; i < ii->xtrack_count; i++) {
236
-
u_var_remove_root(ii->xtracks[i]);
237
-
free(ii->xtracks[i]);
238
-
ii->xtracks[i] = NULL;
239
-
}
240
-
ii->xtrack_count = 0;
241
242
#ifdef XRT_OS_ANDROID
243
android_instance_base_cleanup(&(ii->android), xinst);
···
269
ipc_instance_create(const struct xrt_instance_info *i_info, struct xrt_instance **out_xinst)
270
{
271
struct ipc_client_instance *ii = U_TYPED_CALLOC(struct ipc_client_instance);
272
ii->base.create_system = ipc_client_instance_create_system;
273
ii->base.get_prober = ipc_client_instance_get_prober;
274
ii->base.destroy = ipc_client_instance_destroy;
···
294
free(ii);
295
return xret;
296
}
297
-
298
-
uint32_t count = 0;
299
-
struct xrt_tracking_origin *xtrack = NULL;
300
-
struct ipc_shared_memory *ism = ii->ipc_c.ism;
301
-
302
-
// Query the server for how many tracking origins it has.
303
-
count = 0;
304
-
for (uint32_t i = 0; i < ism->itrack_count; i++) {
305
-
xtrack = U_TYPED_CALLOC(struct xrt_tracking_origin);
306
-
307
-
memcpy(xtrack->name, ism->itracks[i].name, sizeof(xtrack->name));
308
-
309
-
xtrack->type = ism->itracks[i].type;
310
-
xtrack->initial_offset = ism->itracks[i].offset;
311
-
ii->xtracks[count++] = xtrack;
312
-
313
-
u_var_add_root(xtrack, "Tracking origin", true);
314
-
u_var_add_ro_text(xtrack, xtrack->name, "name");
315
-
u_var_add_pose(xtrack, &xtrack->initial_offset, "offset");
316
-
}
317
-
318
-
ii->xtrack_count = count;
319
-
320
-
// Query the server for how many devices it has.
321
-
count = 0;
322
-
for (uint32_t i = 0; i < ism->isdev_count; i++) {
323
-
struct ipc_shared_device *isdev = &ism->isdevs[i];
324
-
xtrack = ii->xtracks[isdev->tracking_origin_index];
325
-
326
-
if (isdev->device_type == XRT_DEVICE_TYPE_HMD) {
327
-
ii->xdevs[count++] = ipc_client_hmd_create(&ii->ipc_c, xtrack, i);
328
-
} else {
329
-
ii->xdevs[count++] = ipc_client_device_create(&ii->ipc_c, xtrack, i);
330
-
}
331
-
}
332
-
333
-
ii->xdev_count = count;
334
335
ii->base.startup_timestamp = ii->ipc_c.ism->startup_timestamp;
336
···
1
// Copyright 2020-2024, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
79
80
struct ipc_connection ipc_c;
81
82
#ifdef XRT_OS_ANDROID
83
struct android_instance_base android;
84
#endif
···
131
*/
132
133
static xrt_result_t
134
+
ipc_client_instance_is_system_available(struct xrt_instance *xinst, bool *out_available)
135
+
{
136
+
struct ipc_client_instance *ii = ipc_client_instance(xinst);
137
+
xrt_result_t xret = ipc_call_instance_is_system_available(&ii->ipc_c, out_available);
138
+
IPC_CHK_ALWAYS_RET(&ii->ipc_c, xret, "ipc_call_instance_is_system_available");
139
+
}
140
+
141
+
static xrt_result_t
142
ipc_client_instance_create_system(struct xrt_instance *xinst,
143
struct xrt_system **out_xsys,
144
struct xrt_system_devices **out_xsysd,
···
154
assert(*out_xsysd == NULL);
155
assert(out_xsysc == NULL || *out_xsysc == NULL);
156
157
struct xrt_system_compositor *xsysc = NULL;
158
159
// Allocate a helper xrt_system_devices struct.
160
+
struct ipc_client_system_devices *icsd = ipc_client_system_devices_create(&ii->ipc_c);
161
+
struct xrt_system_devices *xsysd = &icsd->base.base;
162
+
163
+
uint32_t count = 0;
164
+
struct xrt_tracking_origin *xtrack = NULL;
165
+
struct ipc_shared_memory *ism = ii->ipc_c.ism;
166
167
+
// Query the server for how many tracking origins it has.
168
+
count = 0;
169
+
for (uint32_t i = 0; i < ism->itrack_count; i++) {
170
+
xtrack = U_TYPED_CALLOC(struct xrt_tracking_origin);
171
+
172
+
memcpy(xtrack->name, ism->itracks[i].name, sizeof(xtrack->name));
173
+
174
+
xtrack->type = ism->itracks[i].type;
175
+
xtrack->initial_offset = ism->itracks[i].offset;
176
+
icsd->xtracks[count++] = xtrack;
177
+
178
+
u_var_add_root(xtrack, "Tracking origin", true);
179
+
u_var_add_ro_text(xtrack, xtrack->name, "name");
180
+
u_var_add_pose(xtrack, &xtrack->initial_offset, "offset");
181
+
}
182
+
icsd->xtrack_count = count;
183
+
184
+
// Query the server for how many devices it has.
185
+
count = 0;
186
+
for (uint32_t i = 0; i < ism->isdev_count; i++) {
187
+
struct ipc_shared_device *isdev = &ism->isdevs[i];
188
+
xtrack = icsd->xtracks[isdev->tracking_origin_index];
189
+
190
+
if (isdev->device_type == XRT_DEVICE_TYPE_HMD) {
191
+
xsysd->xdevs[count++] = ipc_client_hmd_create(&ii->ipc_c, xtrack, i);
192
+
} else {
193
+
xsysd->xdevs[count++] = ipc_client_device_create(&ii->ipc_c, xtrack, i);
194
+
}
195
}
196
+
xsysd->xdev_count = count;
197
198
#define SET_ROLE(ROLE) \
199
do { \
···
261
262
// service considers us to be connected until fd is closed
263
ipc_client_connection_fini(&ii->ipc_c);
264
265
#ifdef XRT_OS_ANDROID
266
android_instance_base_cleanup(&(ii->android), xinst);
···
292
ipc_instance_create(const struct xrt_instance_info *i_info, struct xrt_instance **out_xinst)
293
{
294
struct ipc_client_instance *ii = U_TYPED_CALLOC(struct ipc_client_instance);
295
+
ii->base.is_system_available = ipc_client_instance_is_system_available;
296
ii->base.create_system = ipc_client_instance_create_system;
297
ii->base.get_prober = ipc_client_instance_get_prober;
298
ii->base.destroy = ipc_client_instance_destroy;
···
318
free(ii);
319
return xret;
320
}
321
322
ii->base.startup_timestamp = ii->ipc_c.ism->startup_timestamp;
323
+25
src/xrt/ipc/client/ipc_client_space_overseer.c
+25
src/xrt/ipc/client/ipc_client_space_overseer.c
···
1
// Copyright 2023, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
317
return ipc_call_space_set_reference_space_offset(icspo->ipc_c, type, offset);
318
}
319
320
static void
321
destroy(struct xrt_space_overseer *xso)
322
{
···
373
icspo->base.set_tracking_origin_offset = set_tracking_origin_offset;
374
icspo->base.get_reference_space_offset = get_reference_space_offset;
375
icspo->base.set_reference_space_offset = set_reference_space_offset;
376
icspo->base.destroy = destroy;
377
icspo->ipc_c = ipc_c;
378
···
395
396
return &icspo->base;
397
}
···
1
// Copyright 2023, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
318
return ipc_call_space_set_reference_space_offset(icspo->ipc_c, type, offset);
319
}
320
321
+
static xrt_result_t
322
+
add_device(struct xrt_space_overseer *xso, struct xrt_device *xdev)
323
+
{
324
+
return XRT_ERROR_NOT_IMPLEMENTED;
325
+
}
326
+
327
+
static xrt_result_t
328
+
attach_device(struct xrt_space_overseer *xso, struct xrt_device *xdev, struct xrt_space *space)
329
+
{
330
+
// For IPC client, attachable devices are handled on the server side.
331
+
// This should not be called from the client in the typical use case.
332
+
return XRT_ERROR_NOT_IMPLEMENTED;
333
+
}
334
+
335
static void
336
destroy(struct xrt_space_overseer *xso)
337
{
···
388
icspo->base.set_tracking_origin_offset = set_tracking_origin_offset;
389
icspo->base.get_reference_space_offset = get_reference_space_offset;
390
icspo->base.set_reference_space_offset = set_reference_space_offset;
391
+
icspo->base.add_device = add_device;
392
+
icspo->base.attach_device = attach_device;
393
icspo->base.destroy = destroy;
394
icspo->ipc_c = ipc_c;
395
···
412
413
return &icspo->base;
414
}
415
+
416
+
uint32_t
417
+
ipc_client_space_get_id(struct xrt_space *space)
418
+
{
419
+
assert(space != NULL);
420
+
421
+
return ipc_client_space(space)->id;
422
+
}
+3
src/xrt/ipc/client/ipc_client_system.c
+3
src/xrt/ipc/client/ipc_client_system.c
···
1
// Copyright 2020-2023, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
135
ipc_client_system_create(struct ipc_connection *ipc_c, struct xrt_system_compositor *xsysc)
136
{
137
struct ipc_client_system *icsys = U_TYPED_CALLOC(struct ipc_client_system);
138
xrt_result_t xret = ipc_call_system_get_properties(ipc_c, &icsys->base.properties);
139
if (xret != XRT_SUCCESS) {
140
free(icsys);
141
return NULL;
···
1
// Copyright 2020-2023, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
136
ipc_client_system_create(struct ipc_connection *ipc_c, struct xrt_system_compositor *xsysc)
137
{
138
struct ipc_client_system *icsys = U_TYPED_CALLOC(struct ipc_client_system);
139
+
140
xrt_result_t xret = ipc_call_system_get_properties(ipc_c, &icsys->base.properties);
141
+
IPC_CHK_ONLY_PRINT(ipc_c, xret, "ipc_call_system_get_properties");
142
if (xret != XRT_SUCCESS) {
143
free(icsys);
144
return NULL;
+11
-14
src/xrt/ipc/client/ipc_client_system_devices.c
+11
-14
src/xrt/ipc/client/ipc_client_system_devices.c
···
1
// Copyright 2023, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
12
#include "ipc_client_generated.h"
13
14
#include "util/u_system_helpers.h"
15
-
16
-
17
-
struct ipc_client_system_devices
18
-
{
19
-
//! @public Base
20
-
struct u_system_devices base;
21
-
22
-
//! Connection to service.
23
-
struct ipc_connection *ipc_c;
24
-
25
-
struct xrt_reference feature_use[XRT_DEVICE_FEATURE_MAX_ENUM];
26
-
};
27
28
29
/*
···
93
{
94
struct ipc_client_system_devices *usysd = ipc_system_devices(xsysd);
95
96
u_system_devices_close(&usysd->base.base);
97
98
free(usysd);
···
105
*
106
*/
107
108
-
struct xrt_system_devices *
109
ipc_client_system_devices_create(struct ipc_connection *ipc_c)
110
{
111
struct ipc_client_system_devices *icsd = U_TYPED_CALLOC(struct ipc_client_system_devices);
···
115
icsd->base.base.feature_dec = ipc_client_system_devices_feature_dec;
116
icsd->ipc_c = ipc_c;
117
118
-
return &icsd->base.base;
119
}
···
1
// Copyright 2023, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
13
#include "ipc_client_generated.h"
14
15
#include "util/u_system_helpers.h"
16
+
#include "util/u_var.h"
17
18
19
/*
···
83
{
84
struct ipc_client_system_devices *usysd = ipc_system_devices(xsysd);
85
86
+
for (size_t i = 0; i < usysd->xtrack_count; i++) {
87
+
u_var_remove_root(usysd->xtracks[i]);
88
+
free(usysd->xtracks[i]);
89
+
usysd->xtracks[i] = NULL;
90
+
}
91
+
usysd->xtrack_count = 0;
92
+
93
u_system_devices_close(&usysd->base.base);
94
95
free(usysd);
···
102
*
103
*/
104
105
+
struct ipc_client_system_devices *
106
ipc_client_system_devices_create(struct ipc_connection *ipc_c)
107
{
108
struct ipc_client_system_devices *icsd = U_TYPED_CALLOC(struct ipc_client_system_devices);
···
112
icsd->base.base.feature_dec = ipc_client_system_devices_feature_dec;
113
icsd->ipc_c = ipc_c;
114
115
+
return icsd;
116
}
+8
-9
src/xrt/ipc/client/ipc_client_xdev.c
+8
-9
src/xrt/ipc/client/ipc_client_xdev.c
···
391
ipc_client_xdev_init(struct ipc_client_xdev *icx,
392
struct ipc_connection *ipc_c,
393
struct xrt_tracking_origin *xtrack,
394
-
uint32_t device_id)
395
{
396
// Helpers.
397
struct ipc_shared_memory *ism = ipc_c->ism;
···
400
// Important fields.
401
icx->ipc_c = ipc_c;
402
icx->device_id = device_id;
403
404
// Shared implemented functions.
405
icx->base.update_inputs = ipc_client_xdev_update_inputs;
406
-
icx->base.get_tracked_pose = ipc_client_xdev_get_tracked_pose;
407
icx->base.get_hand_tracking = ipc_client_xdev_get_hand_tracking;
408
icx->base.get_face_tracking = ipc_client_xdev_get_face_tracking;
409
icx->base.get_body_skeleton = ipc_client_xdev_get_body_skeleton;
···
420
icx->base.destroy_plane_detection_ext = ipc_client_xdev_destroy_plane_detection_ext;
421
icx->base.get_plane_detection_state_ext = ipc_client_xdev_get_plane_detection_state_ext;
422
icx->base.get_plane_detections_ext = ipc_client_xdev_get_plane_detections_ext;
423
-
424
-
// Not implemented functions, some get overridden.
425
-
icx->base.get_view_poses = u_device_ni_get_view_poses;
426
-
icx->base.compute_distortion = u_device_ni_compute_distortion;
427
-
icx->base.get_visibility_mask = u_device_ni_get_visibility_mask;
428
-
icx->base.is_form_factor_available = u_device_ni_is_form_factor_available;
429
-
icx->base.get_battery_status = u_device_ni_get_battery_status;
430
431
// Copying the information from the isdev.
432
icx->base.device_type = isdev->device_type;
···
391
ipc_client_xdev_init(struct ipc_client_xdev *icx,
392
struct ipc_connection *ipc_c,
393
struct xrt_tracking_origin *xtrack,
394
+
uint32_t device_id,
395
+
u_device_destroy_function_t destroy_fn)
396
{
397
// Helpers.
398
struct ipc_shared_memory *ism = ipc_c->ism;
···
401
// Important fields.
402
icx->ipc_c = ipc_c;
403
icx->device_id = device_id;
404
+
405
+
/*
406
+
* Fill in not implemented or noop versions first,
407
+
* destroy gets filled in by either device or HMD.
408
+
*/
409
+
u_device_populate_function_pointers(&icx->base, ipc_client_xdev_get_tracked_pose, destroy_fn);
410
411
// Shared implemented functions.
412
icx->base.update_inputs = ipc_client_xdev_update_inputs;
413
icx->base.get_hand_tracking = ipc_client_xdev_get_hand_tracking;
414
icx->base.get_face_tracking = ipc_client_xdev_get_face_tracking;
415
icx->base.get_body_skeleton = ipc_client_xdev_get_body_skeleton;
···
426
icx->base.destroy_plane_detection_ext = ipc_client_xdev_destroy_plane_detection_ext;
427
icx->base.get_plane_detection_state_ext = ipc_client_xdev_get_plane_detection_state_ext;
428
icx->base.get_plane_detections_ext = ipc_client_xdev_get_plane_detections_ext;
429
430
// Copying the information from the isdev.
431
icx->base.device_type = isdev->device_type;
+5
-1
src/xrt/ipc/client/ipc_client_xdev.h
+5
-1
src/xrt/ipc/client/ipc_client_xdev.h
···
13
14
#pragma once
15
16
#ifdef __cplusplus
17
extern "C" {
18
#endif
···
58
ipc_client_xdev_init(struct ipc_client_xdev *icx,
59
struct ipc_connection *ipc_c,
60
struct xrt_tracking_origin *xtrack,
61
-
uint32_t device_id);
62
63
/*!
64
* Frees any memory that was allocated as part of init and resets some pointers.
···
13
14
#pragma once
15
16
+
#include "util/u_device.h"
17
+
18
+
19
#ifdef __cplusplus
20
extern "C" {
21
#endif
···
61
ipc_client_xdev_init(struct ipc_client_xdev *icx,
62
struct ipc_connection *ipc_c,
63
struct xrt_tracking_origin *xtrack,
64
+
uint32_t device_id,
65
+
u_device_destroy_function_t destroy_fn);
66
67
/*!
68
* Frees any memory that was allocated as part of init and resets some pointers.
+29
-4
src/xrt/ipc/server/ipc_server.h
+29
-4
src/xrt/ipc/server/ipc_server.h
···
1
// Copyright 2020-2023, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
22
23
#include "shared/ipc_protocol.h"
24
#include "shared/ipc_message_channel.h"
25
26
#include <stdio.h>
27
···
89
{
90
//! Link back to the main server.
91
struct ipc_server *server;
92
93
//! Session for this client.
94
struct xrt_session *xs;
···
188
{
189
//! The actual device.
190
struct xrt_device *xdev;
191
-
192
-
//! Is the IO suppressed for this device.
193
-
bool io_active;
194
};
195
196
/*!
···
329
* @public @memberof ipc_server_mainloop
330
*/
331
int
332
-
ipc_server_mainloop_init(struct ipc_server_mainloop *ml);
333
334
/*!
335
* @brief Poll the mainloop.
···
407
408
struct os_mutex lock;
409
} global_state;
410
};
411
412
413
/*!
414
* Get the current state of a client.
···
1
// Copyright 2020-2023, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
23
24
#include "shared/ipc_protocol.h"
25
#include "shared/ipc_message_channel.h"
26
+
27
+
#include "ipc_server_interface.h"
28
29
#include <stdio.h>
30
···
92
{
93
//! Link back to the main server.
94
struct ipc_server *server;
95
+
96
+
//! Has the system part of the shm initialized.
97
+
bool has_init_shm_system;
98
99
//! Session for this client.
100
struct xrt_session *xs;
···
194
{
195
//! The actual device.
196
struct xrt_device *xdev;
197
};
198
199
/*!
···
332
* @public @memberof ipc_server_mainloop
333
*/
334
int
335
+
ipc_server_mainloop_init(struct ipc_server_mainloop *ml, bool no_stdin);
336
337
/*!
338
* @brief Poll the mainloop.
···
410
411
struct os_mutex lock;
412
} global_state;
413
+
414
+
/*!
415
+
* Callbacks for server events.
416
+
*/
417
+
const struct ipc_server_callbacks *callbacks;
418
+
419
+
/*!
420
+
* User data passed to callbacks.
421
+
*/
422
+
void *callback_data;
423
+
424
+
//! Disable listening on stdin for server stop.
425
+
bool no_stdin;
426
};
427
428
+
/*!
429
+
* Finish setting up the server by creating the system, compositor and devices.
430
+
*
431
+
* @ingroup ipc_server
432
+
*/
433
+
xrt_result_t
434
+
ipc_server_init_system_if_available_locked(struct ipc_server *s,
435
+
volatile struct ipc_client_state *ics,
436
+
bool *out_available);
437
438
/*!
439
* Get the current state of a client.
+41
-17
src/xrt/ipc/server/ipc_server_handler.c
+41
-17
src/xrt/ipc/server/ipc_server_handler.c
···
1
// Copyright 2020-2024, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
387
EXT(meta_body_tracking_full_body_enabled);
388
EXT(meta_body_tracking_calibration_enabled);
389
EXT(fb_face_tracking2_enabled);
390
391
#undef EXT
392
#undef PTT
···
400
}
401
402
xrt_result_t
403
ipc_handle_system_compositor_get_info(volatile struct ipc_client_state *ics,
404
struct xrt_system_compositor_info *out_info)
405
{
···
440
ics->xc = &xcn->base;
441
442
xrt_syscomp_set_state(ics->server->xsysc, ics->xc, ics->client_state.session_visible,
443
-
ics->client_state.session_focused);
444
xrt_syscomp_set_z_order(ics->server->xsysc, ics->xc, ics->client_state.z_order);
445
446
return XRT_SUCCESS;
···
485
.fb_face_tracking2_enabled = ics->client_state.info.fb_face_tracking2_enabled,
486
.meta_body_tracking_full_body_enabled = ics->client_state.info.meta_body_tracking_full_body_enabled,
487
.meta_body_tracking_calibration_enabled = ics->client_state.info.meta_body_tracking_calibration_enabled,
488
};
489
490
return xrt_comp_begin_session(ics->xc, &begin_session_info);
···
1623
}
1624
1625
xrt_result_t
1626
-
ipc_handle_system_toggle_io_device(volatile struct ipc_client_state *ics, uint32_t device_id)
1627
-
{
1628
-
if (device_id >= IPC_MAX_DEVICES) {
1629
-
return XRT_ERROR_IPC_FAILURE;
1630
-
}
1631
-
1632
-
struct ipc_device *idev = &ics->server->idevs[device_id];
1633
-
1634
-
idev->io_active = !idev->io_active;
1635
-
1636
-
return XRT_SUCCESS;
1637
-
}
1638
-
1639
-
xrt_result_t
1640
ipc_handle_swapchain_get_properties(volatile struct ipc_client_state *ics,
1641
const struct xrt_swapchain_create_info *info,
1642
struct xrt_swapchain_create_properties *xsccp)
···
1931
struct xrt_input *dst = &ism->inputs[isdev->first_input_index];
1932
size_t size = sizeof(struct xrt_input) * isdev->input_count;
1933
1934
-
bool io_active = ics->io_active && idev->io_active;
1935
if (io_active) {
1936
memcpy(dst, src, size);
1937
} else {
···
1986
}
1987
1988
// Special case the headpose.
1989
-
bool disabled = (!isdev->io_active || !ics->io_active) && name != XRT_INPUT_GENERIC_HEAD_POSE;
1990
bool active_on_client = input->active;
1991
1992
// We have been disabled but the client hasn't called update.
···
2026
uint32_t id,
2027
const struct xrt_vec3 *fallback_eye_relation,
2028
int64_t at_timestamp_ns,
2029
uint32_t view_count)
2030
{
2031
struct ipc_message_channel *imc = (struct ipc_message_channel *)&ics->imc;
···
2055
xdev, //
2056
fallback_eye_relation, //
2057
at_timestamp_ns, //
2058
view_count, //
2059
&reply.head_relation, //
2060
fovs, //
···
2100
uint32_t id,
2101
const struct xrt_vec3 *default_eye_relation,
2102
int64_t at_timestamp_ns,
2103
uint32_t view_count,
2104
struct ipc_info_get_view_poses_2 *out_info)
2105
{
···
2107
uint32_t device_id = id;
2108
struct xrt_device *xdev = NULL;
2109
GET_XDEV_OR_RETURN(ics, device_id, xdev);
2110
return xrt_device_get_view_poses( //
2111
xdev, //
2112
default_eye_relation, //
2113
at_timestamp_ns, //
2114
view_count, //
2115
&out_info->head_relation, //
2116
out_info->fovs, //
···
2556
GET_XDEV_OR_RETURN(ics, device_id, xdev);
2557
// Get facial expression data.
2558
return xrt_device_get_face_tracking(xdev, facial_expression_type, at_timestamp_ns, out_value);
2559
}
2560
2561
xrt_result_t
···
1
// Copyright 2020-2024, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
388
EXT(meta_body_tracking_full_body_enabled);
389
EXT(meta_body_tracking_calibration_enabled);
390
EXT(fb_face_tracking2_enabled);
391
+
EXT(android_face_tracking_enabled);
392
393
#undef EXT
394
#undef PTT
···
402
}
403
404
xrt_result_t
405
+
ipc_handle_instance_is_system_available(volatile struct ipc_client_state *ics, bool *out_available)
406
+
{
407
+
IPC_TRACE_MARKER();
408
+
409
+
xrt_result_t xret = XRT_SUCCESS;
410
+
411
+
struct ipc_server *s = ics->server;
412
+
413
+
os_mutex_lock(&s->global_state.lock);
414
+
415
+
xret = ipc_server_init_system_if_available_locked(s, ics, out_available);
416
+
IPC_CHK_WITH_GOTO(s, xret, "ipc_server_init_system_if_available_locked", cleanup);
417
+
418
+
cleanup:
419
+
os_mutex_unlock(&s->global_state.lock);
420
+
return xret;
421
+
}
422
+
423
+
xrt_result_t
424
ipc_handle_system_compositor_get_info(volatile struct ipc_client_state *ics,
425
struct xrt_system_compositor_info *out_info)
426
{
···
461
ics->xc = &xcn->base;
462
463
xrt_syscomp_set_state(ics->server->xsysc, ics->xc, ics->client_state.session_visible,
464
+
ics->client_state.session_focused, os_monotonic_get_ns());
465
xrt_syscomp_set_z_order(ics->server->xsysc, ics->xc, ics->client_state.z_order);
466
467
return XRT_SUCCESS;
···
506
.fb_face_tracking2_enabled = ics->client_state.info.fb_face_tracking2_enabled,
507
.meta_body_tracking_full_body_enabled = ics->client_state.info.meta_body_tracking_full_body_enabled,
508
.meta_body_tracking_calibration_enabled = ics->client_state.info.meta_body_tracking_calibration_enabled,
509
+
.android_face_tracking_enabled = ics->client_state.info.android_face_tracking_enabled,
510
};
511
512
return xrt_comp_begin_session(ics->xc, &begin_session_info);
···
1645
}
1646
1647
xrt_result_t
1648
ipc_handle_swapchain_get_properties(volatile struct ipc_client_state *ics,
1649
const struct xrt_swapchain_create_info *info,
1650
struct xrt_swapchain_create_properties *xsccp)
···
1939
struct xrt_input *dst = &ism->inputs[isdev->first_input_index];
1940
size_t size = sizeof(struct xrt_input) * isdev->input_count;
1941
1942
+
bool io_active = ics->io_active;
1943
if (io_active) {
1944
memcpy(dst, src, size);
1945
} else {
···
1994
}
1995
1996
// Special case the headpose.
1997
+
bool disabled = !ics->io_active && name != XRT_INPUT_GENERIC_HEAD_POSE;
1998
bool active_on_client = input->active;
1999
2000
// We have been disabled but the client hasn't called update.
···
2034
uint32_t id,
2035
const struct xrt_vec3 *fallback_eye_relation,
2036
int64_t at_timestamp_ns,
2037
+
enum xrt_view_type view_type,
2038
uint32_t view_count)
2039
{
2040
struct ipc_message_channel *imc = (struct ipc_message_channel *)&ics->imc;
···
2064
xdev, //
2065
fallback_eye_relation, //
2066
at_timestamp_ns, //
2067
+
view_type, //
2068
view_count, //
2069
&reply.head_relation, //
2070
fovs, //
···
2110
uint32_t id,
2111
const struct xrt_vec3 *default_eye_relation,
2112
int64_t at_timestamp_ns,
2113
+
enum xrt_view_type view_type,
2114
uint32_t view_count,
2115
struct ipc_info_get_view_poses_2 *out_info)
2116
{
···
2118
uint32_t device_id = id;
2119
struct xrt_device *xdev = NULL;
2120
GET_XDEV_OR_RETURN(ics, device_id, xdev);
2121
+
2122
return xrt_device_get_view_poses( //
2123
xdev, //
2124
default_eye_relation, //
2125
at_timestamp_ns, //
2126
+
view_type, //
2127
view_count, //
2128
&out_info->head_relation, //
2129
out_info->fovs, //
···
2569
GET_XDEV_OR_RETURN(ics, device_id, xdev);
2570
// Get facial expression data.
2571
return xrt_device_get_face_tracking(xdev, facial_expression_type, at_timestamp_ns, out_value);
2572
+
}
2573
+
2574
+
xrt_result_t
2575
+
ipc_handle_device_device_get_face_calibration_state_android(volatile struct ipc_client_state *ics,
2576
+
uint32_t id,
2577
+
bool *out_face_is_calibrated)
2578
+
{
2579
+
const uint32_t device_id = id;
2580
+
struct xrt_device *xdev = NULL;
2581
+
GET_XDEV_OR_RETURN(ics, device_id, xdev);
2582
+
return xrt_device_get_face_calibration_state_android(xdev, out_face_is_calibrated);
2583
}
2584
2585
xrt_result_t
+32
src/xrt/ipc/server/ipc_server_interface.h
+32
src/xrt/ipc/server/ipc_server_interface.h
···
36
{
37
//! Information passed onto the debug gui.
38
struct u_debug_gui_create_info udgci;
39
};
40
41
/*!
···
70
* @param[in] data User data given passed into the main function.
71
*/
72
void (*mainloop_leaving)(struct ipc_server *s, struct xrt_instance *xinst, void *data);
73
};
74
75
/*!
···
80
int
81
ipc_server_main_common(const struct ipc_server_main_info *ismi, const struct ipc_server_callbacks *iscb, void *data);
82
83
84
#ifndef XRT_OS_ANDROID
85
···
36
{
37
//! Information passed onto the debug gui.
38
struct u_debug_gui_create_info udgci;
39
+
40
+
//! Flag whether runtime should exit on app disconnect.
41
+
bool exit_on_disconnect;
42
+
43
+
//! Disable listening on stdin for server stop.
44
+
bool no_stdin;
45
};
46
47
/*!
···
76
* @param[in] data User data given passed into the main function.
77
*/
78
void (*mainloop_leaving)(struct ipc_server *s, struct xrt_instance *xinst, void *data);
79
+
80
+
/*!
81
+
* A new client has connected to the IPC server.
82
+
*
83
+
* param s The IPC server.
84
+
* param client_id The ID of the newly connected client.
85
+
* param data User data given passed into the main function.
86
+
*/
87
+
void (*client_connected)(struct ipc_server *s, uint32_t client_id, void *data);
88
+
89
+
/*!
90
+
* A client has disconnected from the IPC server.
91
+
*
92
+
* param s The IPC server.
93
+
* param client_id The ID of the newly connected client.
94
+
* param data User data given passed into the main function.
95
+
*/
96
+
void (*client_disconnected)(struct ipc_server *s, uint32_t client_id, void *data);
97
};
98
99
/*!
···
104
int
105
ipc_server_main_common(const struct ipc_server_main_info *ismi, const struct ipc_server_callbacks *iscb, void *data);
106
107
+
/*!
108
+
* Asks the server to shut down, this call is asynchronous and will return
109
+
* immediately. Use callbacks to be notified when the server stops.
110
+
*
111
+
* @memberof ipc_server
112
+
*/
113
+
int
114
+
ipc_server_stop(struct ipc_server *s);
115
116
#ifndef XRT_OS_ANDROID
117
+1
-1
src/xrt/ipc/server/ipc_server_mainloop_android.c
+1
-1
src/xrt/ipc/server/ipc_server_mainloop_android.c
+5
-12
src/xrt/ipc/server/ipc_server_mainloop_linux.c
+5
-12
src/xrt/ipc/server/ipc_server_mainloop_linux.c
···
1
// Copyright 2020-2021, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
46
#include <systemd/sd-daemon.h>
47
#endif
48
49
-
/*
50
-
* "XRT_NO_STDIN" option disables stdin and prevents monado-service from terminating.
51
-
* This could be useful for situations where there is no proper or in a non-interactive shell.
52
-
* Two example scenarios are:
53
-
* * IDE terminals,
54
-
* * Some scripting environments where monado-service is spawned in the background
55
-
*/
56
-
DEBUG_GET_ONCE_BOOL_OPTION(skip_stdin, "XRT_NO_STDIN", false)
57
58
/*
59
*
···
175
}
176
177
static int
178
-
init_epoll(struct ipc_server_mainloop *ml)
179
{
180
int ret = epoll_create1(EPOLL_CLOEXEC);
181
if (ret < 0) {
···
186
187
struct epoll_event ev = {0};
188
189
-
if (!ml->launched_by_socket && !debug_get_bool_option_skip_stdin()) {
190
// Can't do this when launched by systemd socket activation by
191
// default.
192
// This polls stdin.
···
265
}
266
267
int
268
-
ipc_server_mainloop_init(struct ipc_server_mainloop *ml)
269
{
270
IPC_TRACE_MARKER();
271
···
275
return ret;
276
}
277
278
-
ret = init_epoll(ml);
279
if (ret < 0) {
280
ipc_server_mainloop_deinit(ml);
281
return ret;
···
1
// Copyright 2020-2021, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
47
#include <systemd/sd-daemon.h>
48
#endif
49
50
51
/*
52
*
···
168
}
169
170
static int
171
+
init_epoll(struct ipc_server_mainloop *ml, bool no_stdin)
172
{
173
int ret = epoll_create1(EPOLL_CLOEXEC);
174
if (ret < 0) {
···
179
180
struct epoll_event ev = {0};
181
182
+
if (!ml->launched_by_socket && !no_stdin) {
183
// Can't do this when launched by systemd socket activation by
184
// default.
185
// This polls stdin.
···
258
}
259
260
int
261
+
ipc_server_mainloop_init(struct ipc_server_mainloop *ml, bool no_stdin)
262
{
263
IPC_TRACE_MARKER();
264
···
268
return ret;
269
}
270
271
+
ret = init_epoll(ml, no_stdin);
272
if (ret < 0) {
273
ipc_server_mainloop_deinit(ml);
274
return ret;
+3
-2
src/xrt/ipc/server/ipc_server_mainloop_windows.cpp
+3
-2
src/xrt/ipc/server/ipc_server_mainloop_windows.cpp
···
1
// Copyright 2022, Magic Leap, Inc.
2
// Copyright 2020-2022, Collabora, Ltd.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
218
{
219
IPC_TRACE_MARKER();
220
221
-
if (_kbhit()) {
222
U_LOG_E("console input! exiting...");
223
ipc_server_handle_shutdown_signal(vs);
224
return;
···
249
}
250
251
int
252
-
ipc_server_mainloop_init(struct ipc_server_mainloop *ml)
253
{
254
IPC_TRACE_MARKER();
255
···
1
// Copyright 2022, Magic Leap, Inc.
2
// Copyright 2020-2022, Collabora, Ltd.
3
+
// Copyright 2025, NVIDIA CORPORATION.
4
// SPDX-License-Identifier: BSL-1.0
5
/*!
6
* @file
···
219
{
220
IPC_TRACE_MARKER();
221
222
+
if (!vs->no_stdin && _kbhit()) {
223
U_LOG_E("console input! exiting...");
224
ipc_server_handle_shutdown_signal(vs);
225
return;
···
250
}
251
252
int
253
+
ipc_server_mainloop_init(struct ipc_server_mainloop *ml, bool no_stdin)
254
{
255
IPC_TRACE_MARKER();
256
+29
-3
src/xrt/ipc/server/ipc_server_per_client_thread.c
+29
-3
src/xrt/ipc/server/ipc_server_per_client_thread.c
···
1
// Copyright 2020-2023, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
200
{
201
U_TRACE_SET_THREAD_NAME("IPC Client");
202
203
-
IPC_INFO(ics->server, "Client %u connected", ics->client_state.id);
204
205
// Claim the client fd.
206
int epoll_fd = setup_epoll(ics);
···
231
232
// Detect clients disconnecting gracefully.
233
if (ret > 0 && (event.events & EPOLLHUP) != 0) {
234
-
IPC_INFO(ics->server, "Client disconnected.");
235
break;
236
}
237
···
249
break;
250
}
251
252
// Read the whole command now that we know its size
253
uint8_t buf[IPC_BUF_SIZE] = {0};
254
···
274
close(epoll_fd);
275
epoll_fd = -1;
276
277
// Following code is same for all platforms.
278
common_shutdown(ics);
279
}
···
297
{
298
U_TRACE_SET_THREAD_NAME("IPC Client");
299
300
-
IPC_INFO(ics->server, "Client connected");
301
302
while (ics->server->running) {
303
uint8_t buf[IPC_BUF_SIZE] = {0};
···
353
break;
354
}
355
}
356
357
// Following code is same for all platforms.
358
common_shutdown(ics);
···
1
// Copyright 2020-2023, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
201
{
202
U_TRACE_SET_THREAD_NAME("IPC Client");
203
204
+
// Call the client connected callback.
205
+
ics->server->callbacks->client_connected( //
206
+
ics->server, //
207
+
ics->client_state.id, //
208
+
ics->server->callback_data); //
209
210
// Claim the client fd.
211
int epoll_fd = setup_epoll(ics);
···
236
237
// Detect clients disconnecting gracefully.
238
if (ret > 0 && (event.events & EPOLLHUP) != 0) {
239
break;
240
}
241
···
253
break;
254
}
255
256
+
// This needs to hold true.
257
+
if (cmd_size > IPC_BUF_SIZE) {
258
+
IPC_ERROR(ics->server, "Command too large! (%u > %u)", (uint32_t)cmd_size, IPC_BUF_SIZE);
259
+
break;
260
+
}
261
+
262
// Read the whole command now that we know its size
263
uint8_t buf[IPC_BUF_SIZE] = {0};
264
···
284
close(epoll_fd);
285
epoll_fd = -1;
286
287
+
// Call the client disconnected callback.
288
+
ics->server->callbacks->client_disconnected( //
289
+
ics->server, //
290
+
ics->client_state.id, //
291
+
ics->server->callback_data); //
292
+
293
// Following code is same for all platforms.
294
common_shutdown(ics);
295
}
···
313
{
314
U_TRACE_SET_THREAD_NAME("IPC Client");
315
316
+
// Call the client connected callback.
317
+
ics->server->callbacks->client_connected( //
318
+
ics->server, //
319
+
ics->client_state.id, //
320
+
ics->server->callback_data); //
321
322
while (ics->server->running) {
323
uint8_t buf[IPC_BUF_SIZE] = {0};
···
373
break;
374
}
375
}
376
+
377
+
// Call the client disconnected callback.
378
+
ics->server->callbacks->client_disconnected( //
379
+
ics->server, //
380
+
ics->client_state.id, //
381
+
ics->server->callback_data); //
382
383
// Following code is same for all platforms.
384
common_shutdown(ics);
+164
-48
src/xrt/ipc/server/ipc_server_process.c
+164
-48
src/xrt/ipc/server/ipc_server_process.c
···
57
*
58
*/
59
60
-
DEBUG_GET_ONCE_BOOL_OPTION(exit_on_disconnect, "IPC_EXIT_ON_DISCONNECT", false)
61
DEBUG_GET_ONCE_BOOL_OPTION(exit_when_idle, "IPC_EXIT_WHEN_IDLE", false)
62
DEBUG_GET_ONCE_NUM_OPTION(exit_when_idle_delay_ms, "IPC_EXIT_WHEN_IDLE_DELAY_MS", 5000)
63
DEBUG_GET_ONCE_LOG_OPTION(ipc_log, "IPC_LOG", U_LOGGING_INFO)
64
65
66
/*
···
90
static void
91
init_idev(struct ipc_device *idev, struct xrt_device *xdev)
92
{
93
-
if (xdev != NULL) {
94
-
idev->io_active = true;
95
-
idev->xdev = xdev;
96
-
} else {
97
-
idev->io_active = false;
98
-
}
99
}
100
101
static void
102
teardown_idev(struct ipc_device *idev)
103
{
104
-
idev->io_active = false;
105
}
106
107
static void
···
280
}
281
282
XRT_CHECK_RESULT static xrt_result_t
283
-
init_shm(struct ipc_server *s, volatile struct ipc_client_state *cs)
284
{
285
const size_t size = sizeof(struct ipc_shared_memory);
286
xrt_shmem_handle_t handle;
287
288
-
xrt_result_t xret = ipc_shmem_create(size, &handle, (void **)&s->isms[cs->server_thread_index]);
289
IPC_CHK_AND_RET(s, xret, "ipc_shmem_create");
290
291
// we have a filehandle, we will pass this to our client
292
-
cs->ism_handle = handle;
293
294
295
/*
296
*
297
* Setup the shared memory state.
···
300
301
uint32_t count = 0;
302
struct ipc_shared_memory *ism = s->isms[cs->server_thread_index];
303
-
304
-
ism->startup_timestamp = os_monotonic_get_ns();
305
306
// Setup the tracking origins.
307
count = 0;
···
402
403
// Setup the HMD
404
// set view count
405
-
assert(s->xsysd->static_roles.head->hmd);
406
-
ism->hmd.view_count = s->xsysd->static_roles.head->hmd->view_count;
407
-
for (uint32_t view = 0; view < s->xsysd->static_roles.head->hmd->view_count; ++view) {
408
-
ism->hmd.views[view].display.w_pixels = s->xsysd->static_roles.head->hmd->views[view].display.w_pixels;
409
-
ism->hmd.views[view].display.h_pixels = s->xsysd->static_roles.head->hmd->views[view].display.h_pixels;
410
-
}
411
412
-
for (size_t i = 0; i < s->xsysd->static_roles.head->hmd->blend_mode_count; i++) {
413
-
// Not super necessary, we also do this assert in oxr_system.c
414
-
assert(u_verify_blend_mode_valid(s->xsysd->static_roles.head->hmd->blend_modes[i]));
415
-
ism->hmd.blend_modes[i] = s->xsysd->static_roles.head->hmd->blend_modes[i];
416
}
417
-
ism->hmd.blend_mode_count = s->xsysd->static_roles.head->hmd->blend_mode_count;
418
419
// Finally tell the client how many devices we have.
420
ism->isdev_count = count;
···
424
ism->roles.eyes = find_xdev_index(s, s->xsysd->static_roles.eyes);
425
ism->roles.face = find_xdev_index(s, s->xsysd->static_roles.face);
426
ism->roles.body = find_xdev_index(s, s->xsysd->static_roles.body);
427
#define SET_HT_ROLE(SRC) \
428
ism->roles.hand_tracking.SRC.left = find_xdev_index(s, s->xsysd->static_roles.hand_tracking.SRC.left); \
429
ism->roles.hand_tracking.SRC.right = find_xdev_index(s, s->xsysd->static_roles.hand_tracking.SRC.right);
430
SET_HT_ROLE(unobstructed)
431
SET_HT_ROLE(conforming)
432
#undef SET_HT_ROLE
433
-
434
-
// Fill out git version info.
435
-
snprintf(ism->u_git_tag, IPC_VERSION_NAME_LEN, "%s", u_git_tag);
436
-
437
-
return XRT_SUCCESS;
438
}
439
440
static void
···
455
}
456
457
static xrt_result_t
458
-
init_all(struct ipc_server *s, enum u_logging_level log_level)
459
{
460
xrt_result_t xret = XRT_SUCCESS;
461
int ret;
···
463
// First order of business set the log level.
464
s->log_level = log_level;
465
466
// This should never fail.
467
ret = os_mutex_init(&s->global_state.lock);
468
if (ret < 0) {
···
480
481
// Yes we should be running.
482
s->running = true;
483
-
s->exit_on_disconnect = debug_get_bool_option_exit_on_disconnect();
484
s->exit_when_idle = debug_get_bool_option_exit_when_idle();
485
s->last_client_disconnect_ns = 0;
486
uint64_t delay_ms = debug_get_num_option_exit_when_idle_delay_ms();
···
489
xret = xrt_instance_create(NULL, &s->xinst);
490
IPC_CHK_WITH_GOTO(s, xret, "xrt_instance_create", error);
491
492
-
xret = xrt_instance_create_system(s->xinst, &s->xsys, &s->xsysd, &s->xso, &s->xsysc);
493
-
IPC_CHK_WITH_GOTO(s, xret, "xrt_instance_create_system", error);
494
-
495
-
// Always succeeds.
496
-
init_idevs(s);
497
-
init_tracking_origins(s);
498
-
499
-
ret = ipc_server_mainloop_init(&s->ml);
500
if (ret < 0) {
501
xret = XRT_ERROR_IPC_MAINLOOP_FAILED_TO_INIT;
502
}
···
599
ics->client_state.z_order = z_order;
600
601
if (ics->xc != NULL) {
602
-
xrt_syscomp_set_state(ics->server->xsysc, ics->xc, visible, focused);
603
xrt_syscomp_set_z_order(ics->server->xsysc, ics->xc, z_order);
604
}
605
}
···
771
return XRT_SUCCESS;
772
}
773
774
775
/*
776
*
···
779
*/
780
781
xrt_result_t
782
ipc_server_get_client_app_state(struct ipc_server *s, uint32_t client_id, struct ipc_app_state *out_ias)
783
{
784
os_mutex_lock(&s->global_state.lock);
···
937
it->state = IPC_THREAD_STARTING;
938
939
// Allocate a new ID, avoid zero.
940
-
//! @todo validate ID.
941
-
uint32_t id = ++vs->id_generator;
942
943
// Reset everything.
944
U_ZERO((struct ipc_client_state *)ics);
945
946
// Set state.
947
ics->client_state.id = id;
948
ics->imc.ipc_handle = ipc_handle;
949
ics->server = vs;
···
955
ics->plane_detection_ids = NULL;
956
ics->plane_detection_xdev = NULL;
957
958
-
xrt_result_t xret = init_shm(vs, ics);
959
if (xret != XRT_SUCCESS) {
960
961
// Unlock when we are done.
···
995
// Allocate the server itself.
996
struct ipc_server *s = U_TYPED_CALLOC(struct ipc_server);
997
998
#ifdef XRT_OS_WINDOWS
999
timeBeginPeriod(1);
1000
#endif
···
1006
*/
1007
u_debug_gui_create(&ismi->udgci, &s->debug_gui);
1008
1009
-
xret = init_all(s, log_level);
1010
U_LOG_CHK_ONLY_PRINT(log_level, xret, "init_all");
1011
if (xret != XRT_SUCCESS) {
1012
-
// Propegate the failure.
1013
callbacks->init_failed(xret, data);
1014
u_debug_gui_stop(&s->debug_gui);
1015
free(s);
1016
return -1;
1017
}
1018
1019
// Start the debug UI now (if enabled).
1020
u_debug_gui_start(s->debug_gui, s->xinst, s->xsysd);
1021
-
1022
-
// Tell the callbacks we are entering the main-loop.
1023
-
callbacks->mainloop_entering(s, s->xinst, data);
1024
1025
// Main loop.
1026
ret = main_loop(s);
···
1044
return ret;
1045
}
1046
1047
1048
#ifndef XRT_OS_ANDROID
1049
···
1071
// No-op
1072
}
1073
1074
int
1075
ipc_server_main(int argc, char **argv, const struct ipc_server_main_info *ismi)
1076
{
···
1078
.init_failed = init_failed,
1079
.mainloop_entering = mainloop_entering,
1080
.mainloop_leaving = mainloop_leaving,
1081
};
1082
1083
return ipc_server_main_common(ismi, &callbacks, NULL);
···
57
*
58
*/
59
60
DEBUG_GET_ONCE_BOOL_OPTION(exit_when_idle, "IPC_EXIT_WHEN_IDLE", false)
61
DEBUG_GET_ONCE_NUM_OPTION(exit_when_idle_delay_ms, "IPC_EXIT_WHEN_IDLE_DELAY_MS", 5000)
62
DEBUG_GET_ONCE_LOG_OPTION(ipc_log, "IPC_LOG", U_LOGGING_INFO)
63
+
64
+
/*
65
+
* "XRT_NO_STDIN" option disables stdin and prevents monado-service from terminating.
66
+
* This could be useful for situations where there is no proper or in a non-interactive shell.
67
+
* Two example scenarios are:
68
+
* * IDE terminals,
69
+
* * Some scripting environments where monado-service is spawned in the background
70
+
*/
71
+
DEBUG_GET_ONCE_BOOL_OPTION(no_stdin, "XRT_NO_STDIN", false)
72
73
74
/*
···
98
static void
99
init_idev(struct ipc_device *idev, struct xrt_device *xdev)
100
{
101
+
idev->xdev = xdev;
102
}
103
104
static void
105
teardown_idev(struct ipc_device *idev)
106
{
107
+
idev->xdev = NULL;
108
}
109
110
static void
···
283
}
284
285
XRT_CHECK_RESULT static xrt_result_t
286
+
init_shm_and_instance_state(struct ipc_server *s, volatile struct ipc_client_state *ics)
287
{
288
const size_t size = sizeof(struct ipc_shared_memory);
289
xrt_shmem_handle_t handle;
290
291
+
xrt_result_t xret = ipc_shmem_create(size, &handle, (void **)&s->isms[ics->server_thread_index]);
292
IPC_CHK_AND_RET(s, xret, "ipc_shmem_create");
293
294
// we have a filehandle, we will pass this to our client
295
+
ics->ism_handle = handle;
296
+
297
+
// Convenience
298
+
struct ipc_shared_memory *ism = s->isms[ics->server_thread_index];
299
300
+
// Clients expect git version info and timestamp available upon connect.
301
+
snprintf(ism->u_git_tag, IPC_VERSION_NAME_LEN, "%s", u_git_tag);
302
303
+
// Used to synchronize all client's xrt_instance::startup_timestamp.
304
+
ism->startup_timestamp = os_monotonic_get_ns();
305
+
306
+
return XRT_SUCCESS;
307
+
}
308
+
309
+
static void
310
+
init_system_shm_state(struct ipc_server *s, volatile struct ipc_client_state *cs)
311
+
{
312
/*
313
*
314
* Setup the shared memory state.
···
317
318
uint32_t count = 0;
319
struct ipc_shared_memory *ism = s->isms[cs->server_thread_index];
320
321
// Setup the tracking origins.
322
count = 0;
···
417
418
// Setup the HMD
419
// set view count
420
+
const struct xrt_device *xhead = s->xsysd->static_roles.head;
421
+
const struct xrt_hmd_parts *xhmd = xhead != NULL ? xhead->hmd : NULL;
422
+
U_ZERO(&ism->hmd);
423
+
if (xhmd != NULL) {
424
+
ism->hmd.view_count = xhmd->view_count;
425
+
for (uint32_t view = 0; view < xhmd->view_count; ++view) {
426
+
ism->hmd.views[view].display.w_pixels = xhmd->views[view].display.w_pixels;
427
+
ism->hmd.views[view].display.h_pixels = xhmd->views[view].display.h_pixels;
428
+
}
429
430
+
for (uint32_t i = 0; i < xhmd->blend_mode_count; i++) {
431
+
// Not super necessary, we also do this assert in oxr_system.c
432
+
assert(u_verify_blend_mode_valid(xhmd->blend_modes[i]));
433
+
ism->hmd.blend_modes[i] = xhmd->blend_modes[i];
434
+
}
435
+
ism->hmd.blend_mode_count = xhmd->blend_mode_count;
436
}
437
438
// Finally tell the client how many devices we have.
439
ism->isdev_count = count;
···
443
ism->roles.eyes = find_xdev_index(s, s->xsysd->static_roles.eyes);
444
ism->roles.face = find_xdev_index(s, s->xsysd->static_roles.face);
445
ism->roles.body = find_xdev_index(s, s->xsysd->static_roles.body);
446
+
447
#define SET_HT_ROLE(SRC) \
448
ism->roles.hand_tracking.SRC.left = find_xdev_index(s, s->xsysd->static_roles.hand_tracking.SRC.left); \
449
ism->roles.hand_tracking.SRC.right = find_xdev_index(s, s->xsysd->static_roles.hand_tracking.SRC.right);
450
SET_HT_ROLE(unobstructed)
451
SET_HT_ROLE(conforming)
452
#undef SET_HT_ROLE
453
}
454
455
static void
···
470
}
471
472
static xrt_result_t
473
+
init_all(struct ipc_server *s,
474
+
enum u_logging_level log_level,
475
+
const struct ipc_server_callbacks *callbacks,
476
+
void *callback_data,
477
+
bool exit_on_disconnect)
478
{
479
xrt_result_t xret = XRT_SUCCESS;
480
int ret;
···
482
// First order of business set the log level.
483
s->log_level = log_level;
484
485
+
// Store callbacks and data
486
+
s->callbacks = callbacks;
487
+
s->callback_data = callback_data;
488
+
489
// This should never fail.
490
ret = os_mutex_init(&s->global_state.lock);
491
if (ret < 0) {
···
503
504
// Yes we should be running.
505
s->running = true;
506
+
s->exit_on_disconnect = exit_on_disconnect;
507
s->exit_when_idle = debug_get_bool_option_exit_when_idle();
508
s->last_client_disconnect_ns = 0;
509
uint64_t delay_ms = debug_get_num_option_exit_when_idle_delay_ms();
···
512
xret = xrt_instance_create(NULL, &s->xinst);
513
IPC_CHK_WITH_GOTO(s, xret, "xrt_instance_create", error);
514
515
+
ret = ipc_server_mainloop_init(&s->ml, s->no_stdin);
516
if (ret < 0) {
517
xret = XRT_ERROR_IPC_MAINLOOP_FAILED_TO_INIT;
518
}
···
615
ics->client_state.z_order = z_order;
616
617
if (ics->xc != NULL) {
618
+
xrt_syscomp_set_state(ics->server->xsysc, ics->xc, visible, focused, os_monotonic_get_ns());
619
xrt_syscomp_set_z_order(ics->server->xsysc, ics->xc, z_order);
620
}
621
}
···
787
return XRT_SUCCESS;
788
}
789
790
+
static uint32_t
791
+
allocate_id_locked(struct ipc_server *s)
792
+
{
793
+
uint32_t id = 0;
794
+
while (id == 0) {
795
+
// Allocate a new one.
796
+
id = ++s->id_generator;
797
+
798
+
for (uint32_t i = 0; i < IPC_MAX_CLIENTS; i++) {
799
+
volatile struct ipc_client_state *ics = &s->threads[i].ics;
800
+
801
+
// If we find the ID, get a new one by setting to zero.
802
+
if (ics->client_state.id == id) {
803
+
id = 0;
804
+
break;
805
+
}
806
+
}
807
+
}
808
+
809
+
// Paranoia.
810
+
if (id == 0) {
811
+
U_LOG_E("Got app(client) id 0, not allowed!");
812
+
assert(id > 0);
813
+
}
814
+
815
+
return id;
816
+
}
817
+
818
819
/*
820
*
···
823
*/
824
825
xrt_result_t
826
+
ipc_server_init_system_if_available_locked(struct ipc_server *s,
827
+
volatile struct ipc_client_state *ics,
828
+
bool *out_available)
829
+
{
830
+
xrt_result_t xret = XRT_SUCCESS;
831
+
832
+
bool available = false;
833
+
834
+
if (s->xsys) {
835
+
available = true;
836
+
} else {
837
+
xret = xrt_instance_is_system_available(s->xinst, &available);
838
+
IPC_CHK_WITH_GOTO(s, xret, "xrt_instance_is_system_available", error);
839
+
840
+
if (available) {
841
+
xret = xrt_instance_create_system(s->xinst, &s->xsys, &s->xsysd, &s->xso, &s->xsysc);
842
+
IPC_CHK_WITH_GOTO(s, xret, "xrt_instance_create_system", error);
843
+
844
+
// Always succeeds.
845
+
init_idevs(s);
846
+
init_tracking_origins(s);
847
+
}
848
+
}
849
+
850
+
if (available && ics != NULL && !ics->has_init_shm_system) {
851
+
init_system_shm_state(s, ics);
852
+
ics->has_init_shm_system = true;
853
+
}
854
+
855
+
if (out_available) {
856
+
*out_available = available;
857
+
}
858
+
859
+
return XRT_SUCCESS;
860
+
861
+
error:
862
+
return xret;
863
+
}
864
+
865
+
xrt_result_t
866
ipc_server_get_client_app_state(struct ipc_server *s, uint32_t client_id, struct ipc_app_state *out_ias)
867
{
868
os_mutex_lock(&s->global_state.lock);
···
1021
it->state = IPC_THREAD_STARTING;
1022
1023
// Allocate a new ID, avoid zero.
1024
+
uint32_t id = allocate_id_locked(vs);
1025
1026
// Reset everything.
1027
U_ZERO((struct ipc_client_state *)ics);
1028
1029
// Set state.
1030
+
ics->local_space_overseer_index = UINT32_MAX;
1031
ics->client_state.id = id;
1032
ics->imc.ipc_handle = ipc_handle;
1033
ics->server = vs;
···
1039
ics->plane_detection_ids = NULL;
1040
ics->plane_detection_xdev = NULL;
1041
1042
+
xrt_result_t xret = init_shm_and_instance_state(vs, ics);
1043
if (xret != XRT_SUCCESS) {
1044
1045
// Unlock when we are done.
···
1079
// Allocate the server itself.
1080
struct ipc_server *s = U_TYPED_CALLOC(struct ipc_server);
1081
1082
+
// Can be set by either.
1083
+
s->no_stdin = ismi->no_stdin || debug_get_bool_option_no_stdin();
1084
+
1085
#ifdef XRT_OS_WINDOWS
1086
timeBeginPeriod(1);
1087
#endif
···
1093
*/
1094
u_debug_gui_create(&ismi->udgci, &s->debug_gui);
1095
1096
+
xret = init_all(s, log_level, callbacks, data, ismi->exit_on_disconnect);
1097
U_LOG_CHK_ONLY_PRINT(log_level, xret, "init_all");
1098
if (xret != XRT_SUCCESS) {
1099
+
// Propagate the failure.
1100
callbacks->init_failed(xret, data);
1101
u_debug_gui_stop(&s->debug_gui);
1102
free(s);
1103
return -1;
1104
}
1105
1106
+
// Tell the callbacks we are entering the main-loop.
1107
+
callbacks->mainloop_entering(s, s->xinst, data);
1108
+
1109
+
// Early init the system. If not available now, will try again per client request.
1110
+
xret = ipc_server_init_system_if_available_locked( //
1111
+
s, //
1112
+
NULL, // optional - ics
1113
+
NULL); // optional - out_available
1114
+
if (xret != XRT_SUCCESS) {
1115
+
U_LOG_CHK_ONLY_PRINT(log_level, xret, "ipc_server_init_system_if_available_locked");
1116
+
}
1117
+
1118
// Start the debug UI now (if enabled).
1119
u_debug_gui_start(s->debug_gui, s->xinst, s->xsysd);
1120
1121
// Main loop.
1122
ret = main_loop(s);
···
1140
return ret;
1141
}
1142
1143
+
int
1144
+
ipc_server_stop(struct ipc_server *s)
1145
+
{
1146
+
s->running = false;
1147
+
return 0;
1148
+
}
1149
1150
#ifndef XRT_OS_ANDROID
1151
···
1173
// No-op
1174
}
1175
1176
+
void
1177
+
client_connected(struct ipc_server *s, uint32_t client_id, void *data)
1178
+
{
1179
+
IPC_INFO(s, "Client %u connected", client_id);
1180
+
}
1181
+
1182
+
void
1183
+
client_disconnected(struct ipc_server *s, uint32_t client_id, void *data)
1184
+
{
1185
+
IPC_INFO(s, "Client %u disconnected", client_id);
1186
+
}
1187
+
1188
int
1189
ipc_server_main(int argc, char **argv, const struct ipc_server_main_info *ismi)
1190
{
···
1192
.init_failed = init_failed,
1193
.mainloop_entering = mainloop_entering,
1194
.mainloop_leaving = mainloop_leaving,
1195
+
.client_connected = client_connected,
1196
+
.client_disconnected = client_disconnected,
1197
};
1198
1199
return ipc_server_main_common(ismi, &callbacks, NULL);
+10
-1
src/xrt/state_trackers/gui/gui_scene_debug.c
+10
-1
src/xrt/state_trackers/gui/gui_scene_debug.c
···
521
igPopItemFlag();
522
igPopStyleVar(1);
523
}
524
}
525
526
static void
···
689
case U_VAR_KIND_POSE: on_pose(name, ptr); break;
690
case U_VAR_KIND_LOG_LEVEL: igCombo_Str(name, (int *)ptr, "Trace\0Debug\0Info\0Warn\0Error\0\0", 5); break;
691
case U_VAR_KIND_RO_TEXT: igText("%s: '%s'", name, (char *)ptr); break;
692
-
case U_VAR_KIND_RO_FTEXT: igText(ptr ? (char *)ptr : "%s", name); break;
693
case U_VAR_KIND_RO_I16: igInputScalar(name, ImGuiDataType_S16, ptr, NULL, NULL, NULL, ro_i_flags); break;
694
case U_VAR_KIND_RO_I32: igInputScalar(name, ImGuiDataType_S32, ptr, NULL, NULL, NULL, ro_i_flags); break;
695
case U_VAR_KIND_RO_U16: igInputScalar(name, ImGuiDataType_U16, ptr, NULL, NULL, NULL, ro_i_flags); break;
···
706
case U_VAR_KIND_GUI_HEADER: assert(false && "Should be handled before this"); break;
707
case U_VAR_KIND_GUI_HEADER_BEGIN: on_gui_header_begin(name, state); break;
708
case U_VAR_KIND_GUI_HEADER_END: on_gui_header_end(); break;
709
case U_VAR_KIND_SINK_DEBUG: on_sink_debug_var(name, ptr, state); break;
710
case U_VAR_KIND_NATIVE_IMAGES_DEBUG: on_native_images_debug_var(name, ptr, state); break;
711
case U_VAR_KIND_DRAGGABLE_F32: on_draggable_f32_var(name, ptr); break;
···
521
igPopItemFlag();
522
igPopStyleVar(1);
523
}
524
+
525
+
// Checking for downed.
526
+
if (disabled) {
527
+
btn->downed = false;
528
+
} else {
529
+
btn->downed = igIsItemHovered(ImGuiHoveredFlags_RectOnly) && igIsMouseDown_Nil(ImGuiMouseButton_Left) &&
530
+
igIsItemActive();
531
+
}
532
}
533
534
static void
···
697
case U_VAR_KIND_POSE: on_pose(name, ptr); break;
698
case U_VAR_KIND_LOG_LEVEL: igCombo_Str(name, (int *)ptr, "Trace\0Debug\0Info\0Warn\0Error\0\0", 5); break;
699
case U_VAR_KIND_RO_TEXT: igText("%s: '%s'", name, (char *)ptr); break;
700
+
case U_VAR_KIND_RO_RAW_TEXT: igText("%s", (char *)ptr); break;
701
case U_VAR_KIND_RO_I16: igInputScalar(name, ImGuiDataType_S16, ptr, NULL, NULL, NULL, ro_i_flags); break;
702
case U_VAR_KIND_RO_I32: igInputScalar(name, ImGuiDataType_S32, ptr, NULL, NULL, NULL, ro_i_flags); break;
703
case U_VAR_KIND_RO_U16: igInputScalar(name, ImGuiDataType_U16, ptr, NULL, NULL, NULL, ro_i_flags); break;
···
714
case U_VAR_KIND_GUI_HEADER: assert(false && "Should be handled before this"); break;
715
case U_VAR_KIND_GUI_HEADER_BEGIN: on_gui_header_begin(name, state); break;
716
case U_VAR_KIND_GUI_HEADER_END: on_gui_header_end(); break;
717
+
case U_VAR_KIND_GUI_SAMELINE: igSameLine(0.0, 4.0f); break;
718
case U_VAR_KIND_SINK_DEBUG: on_sink_debug_var(name, ptr, state); break;
719
case U_VAR_KIND_NATIVE_IMAGES_DEBUG: on_native_images_debug_var(name, ptr, state); break;
720
case U_VAR_KIND_DRAGGABLE_F32: on_draggable_f32_var(name, ptr); break;
+10
-1
src/xrt/state_trackers/gui/gui_scene_remote.c
+10
-1
src/xrt/state_trackers/gui/gui_scene_remote.c
···
413
igBegin("Remote control", NULL, 0);
414
415
#ifdef XRT_BUILD_DRIVER_REMOTE
416
-
if (gr->rc.fd < 0) {
417
on_not_connected(gr, p);
418
} else {
419
on_connected(gr, p);
···
451
452
gr->base.render = scene_render;
453
gr->base.destroy = scene_destroy;
454
gr->rc.fd = -1;
455
456
// GUI input defaults.
457
if (address != NULL) {
···
413
igBegin("Remote control", NULL, 0);
414
415
#ifdef XRT_BUILD_DRIVER_REMOTE
416
+
#ifdef XRT_OS_WINDOWS
417
+
bool socket_invalid = gr->rc.fd == INVALID_SOCKET;
418
+
#else
419
+
bool socket_invalid = gr->rc.fd < 0;
420
+
#endif
421
+
if (socket_invalid) {
422
on_not_connected(gr, p);
423
} else {
424
on_connected(gr, p);
···
456
457
gr->base.render = scene_render;
458
gr->base.destroy = scene_destroy;
459
+
#ifdef XRT_OS_WINDOWS
460
+
gr->rc.fd = INVALID_SOCKET;
461
+
#else
462
gr->rc.fd = -1;
463
+
#endif
464
465
// GUI input defaults.
466
if (address != NULL) {
+2
-2
src/xrt/state_trackers/gui/gui_scene_tracking_overrides.c
+2
-2
src/xrt/state_trackers/gui/gui_scene_tracking_overrides.c
···
11
#include "util/u_misc.h"
12
#include "util/u_format.h"
13
#include "util/u_logging.h"
14
15
#include "util/u_config_json.h"
16
···
23
#include "gui_common.h"
24
#include "gui_imgui.h"
25
26
-
#include "bindings/b_generated_bindings_helpers.h"
27
28
struct gui_tracking_overrides
29
{
···
243
continue;
244
}
245
246
-
const char *name_str = xrt_input_name_string(input_name);
247
bool selected = o->input_name == input_name;
248
if (igCheckbox(name_str, &selected)) {
249
o->input_name = input_name;
···
11
#include "util/u_misc.h"
12
#include "util/u_format.h"
13
#include "util/u_logging.h"
14
+
#include "util/u_pretty_print.h"
15
16
#include "util/u_config_json.h"
17
···
24
#include "gui_common.h"
25
#include "gui_imgui.h"
26
27
28
struct gui_tracking_overrides
29
{
···
243
continue;
244
}
245
246
+
const char *name_str = u_str_xrt_input_name(input_name);
247
bool selected = o->input_name == input_name;
248
if (igCheckbox(name_str, &selected)) {
249
o->input_name = input_name;
+5
-1
src/xrt/state_trackers/oxr/CMakeLists.txt
+5
-1
src/xrt/state_trackers/oxr/CMakeLists.txt
···
106
target_sources(st_oxr PRIVATE oxr_api_body_tracking.c oxr_body_tracking.c)
107
endif()
108
109
+
if(XRT_FEATURE_OPENXR_FACE_TRACKING_ANDROID)
110
+
target_sources(st_oxr PRIVATE oxr_api_face_tracking_android.c oxr_face_tracking_android.c)
111
+
endif()
112
+
113
if(XRT_FEATURE_OPENXR_FACIAL_TRACKING_HTC)
114
+
target_sources(st_oxr PRIVATE oxr_api_face_tracking_htc.c oxr_face_tracking_htc.c)
115
endif()
116
117
if(XRT_FEATURE_OPENXR_FACE_TRACKING2_FB)
+7
-7
src/xrt/state_trackers/oxr/oxr_api_action.c
+7
-7
src/xrt/state_trackers/oxr/oxr_api_action.c
···
1
// Copyright 2019-2023, Collabora, Ltd.
2
-
// Copyright 2023, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
156
os_mutex_unlock(&sess->sys->sync_actions_mutex);
157
}
158
159
-
if (syncInfo->countActiveActionSets == 0) {
160
-
// nothing to do
161
-
return XR_SUCCESS;
162
-
}
163
-
164
for (uint32_t i = 0; i < syncInfo->countActiveActionSets; i++) {
165
struct oxr_action_set *act_set = NULL;
166
OXR_VERIFY_ACTIONSET_NOT_NULL(&log, syncInfo->activeActionSets[i].actionSet, act_set);
167
168
XrResult res = oxr_verify_subaction_path_sync(&log, sess->sys->inst, act_set,
···
238
path_verify_fn_t dpad_path_fn = NULL;
239
path_verify_fn_t dpad_emulator_fn = NULL;
240
ext_verify_fn_t ext_verify_fn = NULL;
241
-
bool has_dpad = inst->extensions.EXT_dpad_binding;
242
243
struct profile_template *interaction_profile_template = NULL;
244
for (uint32_t i = 0; i < ARRAY_SIZE(profile_templates); i++) {
···
1
// Copyright 2019-2023, Collabora, Ltd.
2
+
// Copyright 2023-2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
156
os_mutex_unlock(&sess->sys->sync_actions_mutex);
157
}
158
159
for (uint32_t i = 0; i < syncInfo->countActiveActionSets; i++) {
160
struct oxr_action_set *act_set = NULL;
161
+
162
OXR_VERIFY_ACTIONSET_NOT_NULL(&log, syncInfo->activeActionSets[i].actionSet, act_set);
163
164
XrResult res = oxr_verify_subaction_path_sync(&log, sess->sys->inst, act_set,
···
234
path_verify_fn_t dpad_path_fn = NULL;
235
path_verify_fn_t dpad_emulator_fn = NULL;
236
ext_verify_fn_t ext_verify_fn = NULL;
237
+
#ifdef OXR_HAVE_EXT_dpad_binding
238
+
const bool has_dpad = inst->extensions.EXT_dpad_binding;
239
+
#else
240
+
const bool has_dpad = false;
241
+
#endif
242
243
struct profile_template *interaction_profile_template = NULL;
244
for (uint32_t i = 0; i < ARRAY_SIZE(profile_templates); i++) {
-90
src/xrt/state_trackers/oxr/oxr_api_face_tracking.c
-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
+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
+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
+24
src/xrt/state_trackers/oxr/oxr_api_funcs.h
···
779
oxr_xrCancelFutureEXT(XrInstance instance, const XrFutureCancelInfoEXT *cancelInfo);
780
#endif
781
782
+
/*
783
+
*
784
+
* oxr_api_face_tracking_android.c
785
+
*
786
+
*/
787
+
788
+
#ifdef OXR_HAVE_ANDROID_face_tracking
789
+
XRAPI_ATTR XrResult XRAPI_CALL
790
+
oxr_xrCreateFaceTrackerANDROID(XrSession session,
791
+
const XrFaceTrackerCreateInfoANDROID *createInfo,
792
+
XrFaceTrackerANDROID *faceTracker);
793
+
794
+
XRAPI_ATTR XrResult XRAPI_CALL
795
+
oxr_xrDestroyFaceTrackerANDROID(XrFaceTrackerANDROID facialTracker);
796
+
797
+
XRAPI_ATTR XrResult XRAPI_CALL
798
+
oxr_xrGetFaceStateANDROID(XrFaceTrackerANDROID faceTracker,
799
+
const XrFaceStateGetInfoANDROID *getInfo,
800
+
XrFaceStateANDROID *faceStateOutput);
801
+
802
+
XRAPI_ATTR XrResult XRAPI_CALL
803
+
oxr_xrGetFaceCalibrationStateANDROID(XrFaceTrackerANDROID faceTracker, XrBool32 *faceIsCalibratedOutput);
804
+
#endif
805
+
806
/*!
807
* @}
808
*/
+50
-10
src/xrt/state_trackers/oxr/oxr_api_instance.c
+50
-10
src/xrt/state_trackers/oxr/oxr_api_instance.c
···
1
// Copyright 2018-2019, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
256
struct oxr_logger log;
257
OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst, "xrResultToString");
258
259
-
#define MAKE_RESULT_CASE(VAL, _) \
260
-
case VAL: snprintf(buffer, XR_MAX_RESULT_STRING_SIZE, #VAL); break;
261
262
switch (value) {
263
XR_LIST_ENUM_XrResult(MAKE_RESULT_CASE);
264
default:
265
-
snprintf(buffer, XR_MAX_RESULT_STRING_SIZE, "XR_UNKNOWN_%s_%d", value < 0 ? "FAILURE" : "SUCCESS",
266
-
value);
267
}
268
// The function snprintf always null terminates.
269
270
return XR_SUCCESS;
271
}
···
282
static_assert(XR_MAX_STRUCTURE_NAME_SIZE == 64,
283
"XR_MAX_STRUCTURE_NAME_SIZE has changed, please update the format string");
284
285
-
#define MAKE_TYPE_CASE(VAL, _) \
286
-
case VAL: snprintf(buffer, XR_MAX_STRUCTURE_NAME_SIZE, "%.63s", #VAL); break;
287
288
switch (value) {
289
XR_LIST_ENUM_XrStructureType(MAKE_TYPE_CASE);
290
-
default: snprintf(buffer, XR_MAX_STRUCTURE_NAME_SIZE, "XR_UNKNOWN_STRUCTURE_TYPE_%d", value);
291
}
292
// The function snprintf always null terminates.
293
#undef MAKE_TYPE_CASE
294
return XR_SUCCESS;
295
}
296
···
311
static_assert(XR_MAX_STRUCTURE_NAME_SIZE_EXTENDED_KHR == 256,
312
"XR_MAX_STRUCTURE_NAME_SIZE_EXTENDED_KHR has changed, please update the format string");
313
314
-
#define MAKE_TYPE_CASE(VAL, _) \
315
-
case VAL: snprintf(buffer, XR_MAX_STRUCTURE_NAME_SIZE_EXTENDED_KHR, "%.255s", #VAL); break;
316
317
switch (value) {
318
XR_LIST_ENUM_XrStructureType(MAKE_TYPE_CASE);
319
-
default: snprintf(buffer, XR_MAX_STRUCTURE_NAME_SIZE_EXTENDED_KHR, "XR_UNKNOWN_STRUCTURE_TYPE_%d", value);
320
}
321
// The function snprintf always null terminates.
322
#undef MAKE_TYPE_CASE
323
return XR_SUCCESS;
324
}
325
#endif // OXR_HAVE_KHR_extended_struct_name_lengths
···
1
// Copyright 2018-2019, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
257
struct oxr_logger log;
258
OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst, "xrResultToString");
259
260
+
// clang-format off
261
+
#define MAKE_RESULT_CASE(VAL, _) case VAL: snprintf(buffer, XR_MAX_RESULT_STRING_SIZE, #VAL); break;
262
+
#define EXT_RESULT(VAL) if (value == VAL) { snprintf(buffer, XR_MAX_RESULT_STRING_SIZE, #VAL); } else
263
+
// clang-format on
264
265
switch (value) {
266
XR_LIST_ENUM_XrResult(MAKE_RESULT_CASE);
267
default:
268
+
// Magic comment to make clang-format happy.
269
+
{
270
+
snprintf(buffer, XR_MAX_RESULT_STRING_SIZE, "XR_UNKNOWN_%s_%d",
271
+
value < 0 ? "FAILURE" : "SUCCESS", value);
272
+
}
273
}
274
+
275
// The function snprintf always null terminates.
276
+
#undef MAKE_RESULT_CASE
277
+
#undef EXT_RESULT
278
279
return XR_SUCCESS;
280
}
···
291
static_assert(XR_MAX_STRUCTURE_NAME_SIZE == 64,
292
"XR_MAX_STRUCTURE_NAME_SIZE has changed, please update the format string");
293
294
+
// clang-format off
295
+
#define MAKE_TYPE_CASE(VAL, _) case VAL: snprintf(buffer, XR_MAX_STRUCTURE_NAME_SIZE, "%.63s", #VAL); break;
296
+
#define EXT_TYPE(VAL) if (value == VAL) { snprintf(buffer, XR_MAX_STRUCTURE_NAME_SIZE, "%.63s", #VAL); } else
297
+
// clang-format on
298
299
switch (value) {
300
XR_LIST_ENUM_XrStructureType(MAKE_TYPE_CASE);
301
+
default:
302
+
#ifdef OXR_HAVE_MNDX_xdev_space
303
+
EXT_TYPE(XR_TYPE_SYSTEM_XDEV_SPACE_PROPERTIES_MNDX)
304
+
EXT_TYPE(XR_TYPE_CREATE_XDEV_LIST_INFO_MNDX)
305
+
EXT_TYPE(XR_TYPE_GET_XDEV_INFO_MNDX)
306
+
EXT_TYPE(XR_TYPE_XDEV_PROPERTIES_MNDX)
307
+
EXT_TYPE(XR_TYPE_CREATE_XDEV_SPACE_INFO_MNDX)
308
+
#endif
309
+
{
310
+
snprintf(buffer, XR_MAX_STRUCTURE_NAME_SIZE, "XR_UNKNOWN_STRUCTURE_TYPE_%d", value);
311
+
}
312
}
313
+
314
// The function snprintf always null terminates.
315
#undef MAKE_TYPE_CASE
316
+
#undef EXT_TYPE
317
+
318
return XR_SUCCESS;
319
}
320
···
335
static_assert(XR_MAX_STRUCTURE_NAME_SIZE_EXTENDED_KHR == 256,
336
"XR_MAX_STRUCTURE_NAME_SIZE_EXTENDED_KHR has changed, please update the format string");
337
338
+
// clang-format off
339
+
#define MAKE_TYPE_CASE(VAL, _) case VAL: snprintf(buffer, XR_MAX_STRUCTURE_NAME_SIZE_EXTENDED_KHR, "%.255s", #VAL); break;
340
+
#define EXT_TYPE(VAL) if (value == VAL) { snprintf(buffer, XR_MAX_STRUCTURE_NAME_SIZE_EXTENDED_KHR, "%.255s", #VAL); } else
341
+
// clang-format on
342
343
switch (value) {
344
XR_LIST_ENUM_XrStructureType(MAKE_TYPE_CASE);
345
+
default:
346
+
#ifdef OXR_HAVE_MNDX_xdev_space
347
+
EXT_TYPE(XR_TYPE_SYSTEM_XDEV_SPACE_PROPERTIES_MNDX)
348
+
EXT_TYPE(XR_TYPE_CREATE_XDEV_LIST_INFO_MNDX)
349
+
EXT_TYPE(XR_TYPE_GET_XDEV_INFO_MNDX)
350
+
EXT_TYPE(XR_TYPE_XDEV_PROPERTIES_MNDX)
351
+
EXT_TYPE(XR_TYPE_CREATE_XDEV_SPACE_INFO_MNDX)
352
+
#endif
353
+
{
354
+
snprintf(buffer, XR_MAX_STRUCTURE_NAME_SIZE_EXTENDED_KHR, "XR_UNKNOWN_STRUCTURE_TYPE_%d",
355
+
value);
356
+
}
357
}
358
+
359
// The function snprintf always null terminates.
360
#undef MAKE_TYPE_CASE
361
+
#undef EXT_TYPE
362
+
363
return XR_SUCCESS;
364
}
365
#endif // OXR_HAVE_KHR_extended_struct_name_lengths
+7
src/xrt/state_trackers/oxr/oxr_api_negotiate.c
+7
src/xrt/state_trackers/oxr/oxr_api_negotiate.c
···
419
ENTRY_IF_EXT(xrCancelFutureEXT, EXT_future);
420
#endif // OXR_HAVE_EXT_future
421
422
+
#ifdef OXR_HAVE_ANDROID_face_tracking
423
+
ENTRY_IF_EXT(xrCreateFaceTrackerANDROID, ANDROID_face_tracking);
424
+
ENTRY_IF_EXT(xrDestroyFaceTrackerANDROID, ANDROID_face_tracking);
425
+
ENTRY_IF_EXT(xrGetFaceCalibrationStateANDROID, ANDROID_face_tracking);
426
+
ENTRY_IF_EXT(xrGetFaceStateANDROID, ANDROID_face_tracking);
427
+
#endif
428
+
429
#ifdef OXR_HAVE_KHR_extended_struct_name_lengths
430
ENTRY_IF_EXT(xrStructureTypeToString2KHR, KHR_extended_struct_name_lengths);
431
#endif // OXR_HAVE_KHR_extended_struct_name_lengths
+11
-12
src/xrt/state_trackers/oxr/oxr_api_session.c
+11
-12
src/xrt/state_trackers/oxr/oxr_api_session.c
···
1
// Copyright 2019-2024, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
99
// in a headless session there is no compositor and primaryViewConfigurationType must be ignored
100
if (sess->compositor != NULL) {
101
OXR_VERIFY_VIEW_CONFIG_TYPE(&log, sess->sys->inst, beginInfo->primaryViewConfigurationType);
102
}
103
104
// Going to effectively double check this, but this gives us an early out.
···
239
OXR_VERIFY_SPACE_NOT_NULL(&log, viewLocateInfo->space, spc);
240
OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, viewState, XR_TYPE_VIEW_STATE);
241
OXR_VERIFY_VIEW_CONFIG_TYPE(&log, sess->sys->inst, viewLocateInfo->viewConfigurationType);
242
243
if (viewCapacityInput == 0) {
244
OXR_VERIFY_ARG_NOT_NULL(&log, viewCountOutput);
···
255
viewLocateInfo->displayTime);
256
}
257
258
-
if (viewLocateInfo->viewConfigurationType != sess->sys->view_config_type) {
259
-
return oxr_error(&log, XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED,
260
-
"(viewConfigurationType == 0x%08x) "
261
-
"unsupported view configuration type",
262
-
viewLocateInfo->viewConfigurationType);
263
-
}
264
-
265
return oxr_session_locate_views( //
266
&log, //
267
sess, //
···
300
visibilityMask->indexCountOutput = 0;
301
302
OXR_VERIFY_VIEW_CONFIG_TYPE(&log, sess->sys->inst, viewConfigurationType);
303
-
if (viewConfigurationType != sess->sys->view_config_type) {
304
-
return oxr_error(&log, XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED,
305
-
"(viewConfigurationType == 0x%08x) unsupported view configuration type",
306
-
viewConfigurationType);
307
-
}
308
309
OXR_VERIFY_VIEW_INDEX(&log, viewIndex);
310
···
1
// Copyright 2019-2024, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
100
// in a headless session there is no compositor and primaryViewConfigurationType must be ignored
101
if (sess->compositor != NULL) {
102
OXR_VERIFY_VIEW_CONFIG_TYPE(&log, sess->sys->inst, beginInfo->primaryViewConfigurationType);
103
+
OXR_VERIFY_VIEW_CONFIG_TYPE_SUPPORTED(&log, sess->sys, beginInfo->primaryViewConfigurationType);
104
}
105
106
// Going to effectively double check this, but this gives us an early out.
···
241
OXR_VERIFY_SPACE_NOT_NULL(&log, viewLocateInfo->space, spc);
242
OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, viewState, XR_TYPE_VIEW_STATE);
243
OXR_VERIFY_VIEW_CONFIG_TYPE(&log, sess->sys->inst, viewLocateInfo->viewConfigurationType);
244
+
OXR_VERIFY_VIEW_CONFIG_TYPE_SUPPORTED(&log, sess->sys, viewLocateInfo->viewConfigurationType);
245
+
246
+
if (viewLocateInfo->viewConfigurationType != sess->current_view_config_type) {
247
+
return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE,
248
+
"(viewLocateInfo->viewConfigurationType == 0x%" PRIx32
249
+
") is not view configuration passed into xrBeginSession(0x%" PRIx32 ")",
250
+
viewLocateInfo->viewConfigurationType, sess->current_view_config_type);
251
+
}
252
253
if (viewCapacityInput == 0) {
254
OXR_VERIFY_ARG_NOT_NULL(&log, viewCountOutput);
···
265
viewLocateInfo->displayTime);
266
}
267
268
return oxr_session_locate_views( //
269
&log, //
270
sess, //
···
303
visibilityMask->indexCountOutput = 0;
304
305
OXR_VERIFY_VIEW_CONFIG_TYPE(&log, sess->sys->inst, viewConfigurationType);
306
+
OXR_VERIFY_VIEW_CONFIG_TYPE_SUPPORTED(&log, sess->sys, viewConfigurationType);
307
308
OXR_VERIFY_VIEW_INDEX(&log, viewIndex);
309
+46
-3
src/xrt/state_trackers/oxr/oxr_api_swapchain.c
+46
-3
src/xrt/state_trackers/oxr/oxr_api_swapchain.c
···
1
// Copyright 2019-2020, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
82
83
// Short hand.
84
struct oxr_instance *inst = sess->sys->inst;
85
86
XrSwapchainUsageFlags flags = 0;
87
flags |= XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT;
···
102
"(createInfo->usageFlags == 0x%04" PRIx64 ") contains invalid flags",
103
createInfo->usageFlags);
104
}
105
bool format_supported = false;
106
-
struct xrt_compositor *c = sess->compositor;
107
-
for (uint32_t i = 0; i < c->info.format_count; i++) {
108
-
if (c->info.formats[i] == createInfo->format) {
109
format_supported = true;
110
break;
111
}
···
115
return oxr_error(&log, XR_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED,
116
"(createInfo->format == 0x%04" PRIx64 ") is not supported", createInfo->format);
117
}
118
119
#ifdef OXR_HAVE_KHR_vulkan_swapchain_format_list
120
const XrVulkanSwapchainFormatListCreateInfoKHR *format_list = NULL;
···
136
}
137
}
138
#endif
139
140
ret = sess->create_swapchain(&log, sess, createInfo, &sc);
141
if (ret != XR_SUCCESS) {
···
1
// Copyright 2019-2020, Collabora, Ltd.
2
+
// Copyright 2024-2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
83
84
// Short hand.
85
struct oxr_instance *inst = sess->sys->inst;
86
+
struct xrt_compositor_info *xc_info = &sess->compositor->info;
87
+
struct xrt_system_compositor_info *xsysc_info = &sess->sys->xsysc->info;
88
+
89
+
90
+
/*
91
+
* Usage flags.
92
+
*/
93
94
XrSwapchainUsageFlags flags = 0;
95
flags |= XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT;
···
110
"(createInfo->usageFlags == 0x%04" PRIx64 ") contains invalid flags",
111
createInfo->usageFlags);
112
}
113
+
114
+
115
+
/*
116
+
* Format.
117
+
*/
118
+
119
bool format_supported = false;
120
+
for (uint32_t i = 0; i < xc_info->format_count; i++) {
121
+
if (xc_info->formats[i] == createInfo->format) {
122
format_supported = true;
123
break;
124
}
···
128
return oxr_error(&log, XR_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED,
129
"(createInfo->format == 0x%04" PRIx64 ") is not supported", createInfo->format);
130
}
131
+
132
+
133
+
/*
134
+
* Format list.
135
+
*/
136
137
#ifdef OXR_HAVE_KHR_vulkan_swapchain_format_list
138
const XrVulkanSwapchainFormatListCreateInfoKHR *format_list = NULL;
···
154
}
155
}
156
#endif
157
+
158
+
159
+
/*
160
+
* Sample count.
161
+
*/
162
+
163
+
if (createInfo->sampleCount == 0) {
164
+
return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE, "(createInfo->sampleCount == 0) must not be zero");
165
+
}
166
+
167
+
// TODO Find the max of the views[0].max.sample_count limits.
168
+
assert(xsysc_info->view_config_count > 0);
169
+
assert(xsysc_info->view_configs[0].view_count > 0);
170
+
uint32_t max_sample_count = xsysc_info->view_configs[0].views[0].max.sample_count;
171
+
172
+
if (createInfo->sampleCount > max_sample_count) {
173
+
return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE,
174
+
"(createInfo->sampleCount == %u) must not be larger then max (%u)",
175
+
createInfo->sampleCount, max_sample_count);
176
+
}
177
+
178
+
179
+
/*
180
+
* Validation done.
181
+
*/
182
183
ret = sess->create_swapchain(&log, sess, createInfo, &sc);
184
if (ret != XR_SUCCESS) {
+26
-10
src/xrt/state_trackers/oxr/oxr_api_system.c
+26
-10
src/xrt/state_trackers/oxr/oxr_api_system.c
···
1
// Copyright 2018-2020, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
64
struct oxr_system *systems[1] = {&inst->system};
65
uint32_t system_count = ARRAY_SIZE(systems);
66
67
-
XrResult ret = oxr_system_select(&log, systems, system_count, getInfo->formFactor, &selected);
68
if (ret != XR_SUCCESS) {
69
-
return ret;
70
}
71
72
*systemId = selected->systemId;
···
121
OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst, "xrEnumerateEnvironmentBlendModes");
122
OXR_VERIFY_SYSTEM_AND_GET(&log, inst, systemId, sys);
123
OXR_VERIFY_VIEW_CONFIG_TYPE(&log, inst, viewConfigurationType);
124
-
125
-
if (viewConfigurationType != sys->view_config_type) {
126
-
return oxr_error(&log, XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED,
127
-
"(viewConfigurationType == 0x%08x) "
128
-
"unsupported view configuration type",
129
-
viewConfigurationType);
130
-
}
131
132
return oxr_system_enumerate_blend_modes(&log, sys, viewConfigurationType, environmentBlendModeCapacityInput,
133
environmentBlendModeCountOutput, environmentBlendModes);
···
146
OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst, "xrGetViewConfigurationProperties");
147
OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, configurationProperties, XR_TYPE_VIEW_CONFIGURATION_PROPERTIES);
148
OXR_VERIFY_SYSTEM_AND_GET(&log, inst, systemId, sys);
149
150
return oxr_system_get_view_conf_properties(&log, sys, viewConfigurationType, configurationProperties);
151
}
···
164
struct oxr_logger log;
165
OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst, "xrEnumerateViewConfigurationViews");
166
OXR_VERIFY_SYSTEM_AND_GET(&log, inst, systemId, sys);
167
168
for (uint32_t i = 0; i < viewCapacityInput; i++) {
169
OXR_VERIFY_ARG_ARRAY_ELEMENT_TYPE(&log, views, i, XR_TYPE_VIEW_CONFIGURATION_VIEW);
···
328
329
OXR_VERIFY_SYSTEM_AND_GET(&log, inst, getInfo->systemId, sys);
330
OXR_VERIFY_ARG_NOT_NULL(&log, vkPhysicalDevice);
331
OXR_VERIFY_XSYSC(&log, sys);
332
333
-
return oxr_vk_get_physical_device(&log, inst, sys, getInfo->vulkanInstance, vkGetInstanceProcAddr,
334
vkPhysicalDevice);
335
}
336
···
393
394
// createInfo->vulkanAllocator can be NULL
395
396
if (createInfo->vulkanCreateInfo->sType != VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO) {
397
return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE,
398
"createInfo->vulkanCreateInfo->sType must be "
···
428
OXR_VERIFY_ARG_NOT_NULL(&log, sys->suggested_vulkan_physical_device);
429
OXR_VERIFY_ARG_NOT_NULL(&log, sys->vulkan_enable2_instance);
430
OXR_VERIFY_XSYSC(&log, sys);
431
432
if (sys->suggested_vulkan_physical_device != createInfo->vulkanPhysicalDevice) {
433
return oxr_error(&log, XR_ERROR_HANDLE_INVALID,
···
1
// Copyright 2018-2020, Collabora, Ltd.
2
+
// Copyright 2024-2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
65
struct oxr_system *systems[1] = {&inst->system};
66
uint32_t system_count = ARRAY_SIZE(systems);
67
68
+
/*
69
+
* This lock is needed to make sure that xrGetSystem can be called from
70
+
* multiple threads. This happens in the CTS.
71
+
*/
72
+
os_mutex_lock(&inst->system_init_lock);
73
+
XrResult ret = oxr_instance_init_system_locked(&log, inst);
74
+
os_mutex_unlock(&inst->system_init_lock);
75
+
76
if (ret != XR_SUCCESS) {
77
+
return ret; // Already logged
78
+
}
79
+
80
+
ret = oxr_system_select(&log, systems, system_count, getInfo->formFactor, &selected);
81
+
if (ret != XR_SUCCESS) {
82
+
return ret; // Already logged
83
}
84
85
*systemId = selected->systemId;
···
134
OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst, "xrEnumerateEnvironmentBlendModes");
135
OXR_VERIFY_SYSTEM_AND_GET(&log, inst, systemId, sys);
136
OXR_VERIFY_VIEW_CONFIG_TYPE(&log, inst, viewConfigurationType);
137
+
OXR_VERIFY_VIEW_CONFIG_TYPE_SUPPORTED(&log, sys, viewConfigurationType);
138
139
return oxr_system_enumerate_blend_modes(&log, sys, viewConfigurationType, environmentBlendModeCapacityInput,
140
environmentBlendModeCountOutput, environmentBlendModes);
···
153
OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst, "xrGetViewConfigurationProperties");
154
OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, configurationProperties, XR_TYPE_VIEW_CONFIGURATION_PROPERTIES);
155
OXR_VERIFY_SYSTEM_AND_GET(&log, inst, systemId, sys);
156
+
OXR_VERIFY_VIEW_CONFIG_TYPE(&log, inst, viewConfigurationType);
157
+
OXR_VERIFY_VIEW_CONFIG_TYPE_SUPPORTED(&log, sys, viewConfigurationType);
158
159
return oxr_system_get_view_conf_properties(&log, sys, viewConfigurationType, configurationProperties);
160
}
···
173
struct oxr_logger log;
174
OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst, "xrEnumerateViewConfigurationViews");
175
OXR_VERIFY_SYSTEM_AND_GET(&log, inst, systemId, sys);
176
+
OXR_VERIFY_VIEW_CONFIG_TYPE(&log, inst, viewConfigurationType);
177
+
OXR_VERIFY_VIEW_CONFIG_TYPE_SUPPORTED(&log, sys, viewConfigurationType);
178
179
for (uint32_t i = 0; i < viewCapacityInput; i++) {
180
OXR_VERIFY_ARG_ARRAY_ELEMENT_TYPE(&log, views, i, XR_TYPE_VIEW_CONFIGURATION_VIEW);
···
339
340
OXR_VERIFY_SYSTEM_AND_GET(&log, inst, getInfo->systemId, sys);
341
OXR_VERIFY_ARG_NOT_NULL(&log, vkPhysicalDevice);
342
+
OXR_VERIFY_ARG_NOT_NULL(&log, sys->vk_get_instance_proc_addr);
343
OXR_VERIFY_XSYSC(&log, sys);
344
345
+
return oxr_vk_get_physical_device(&log, inst, sys, getInfo->vulkanInstance, sys->vk_get_instance_proc_addr,
346
vkPhysicalDevice);
347
}
348
···
405
406
// createInfo->vulkanAllocator can be NULL
407
408
+
sys->vk_get_instance_proc_addr = createInfo->pfnGetInstanceProcAddr;
409
+
410
if (createInfo->vulkanCreateInfo->sType != VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO) {
411
return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE,
412
"createInfo->vulkanCreateInfo->sType must be "
···
442
OXR_VERIFY_ARG_NOT_NULL(&log, sys->suggested_vulkan_physical_device);
443
OXR_VERIFY_ARG_NOT_NULL(&log, sys->vulkan_enable2_instance);
444
OXR_VERIFY_XSYSC(&log, sys);
445
+
446
+
sys->vk_get_instance_proc_addr = createInfo->pfnGetInstanceProcAddr;
447
448
if (sys->suggested_vulkan_physical_device != createInfo->vulkanPhysicalDevice) {
449
return oxr_error(&log, XR_ERROR_HANDLE_INVALID,
+56
-11
src/xrt/state_trackers/oxr/oxr_api_verify.h
+56
-11
src/xrt/state_trackers/oxr/oxr_api_verify.h
···
1
// Copyright 2018-2024, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
22
struct oxr_action_set;
23
struct oxr_extension_status;
24
struct oxr_instance;
25
struct oxr_logger;
26
struct oxr_subaction_paths;
27
···
95
#define OXR_VERIFY_FUTURE_AND_INIT_LOG(log, thing, new_thing, name) \
96
OXR_VERIFY_AND_SET_AND_INIT(log, thing, new_thing, oxr_future_ext, FUTURE, name, new_thing->inst); \
97
OXR_VERIFY_FUTURE_VALID(log, new_thing)
98
// clang-format on
99
100
#define OXR_VERIFY_INSTANCE_NOT_NULL(log, arg, new_arg) OXR_VERIFY_SET(log, arg, new_arg, oxr_instance, INSTANCE);
···
200
} \
201
} while (false)
202
203
#define OXR_VERIFY_SUBACTION_PATHS(log, count, paths) \
204
do { \
205
if (count > 0 && paths == NULL) { \
···
232
\
233
if (!math_vec3_validate((struct xrt_vec3 *)&p.position)) { \
234
return oxr_error(log, XR_ERROR_POSE_INVALID, "(" #p ".position) is not valid"); \
235
} \
236
} while (false)
237
···
243
} \
244
} while (false)
245
246
#define OXR_VERIFY_VIEW_INDEX(log, index) \
247
do { \
248
if (index > 2) { \
···
308
} \
309
} while (false)
310
311
-
#define OXR_VERIFY_FORM_FACTOR(log, form_factor) \
312
-
do { \
313
-
XrFormFactor _form_factor = (form_factor); \
314
-
if (_form_factor != XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY && \
315
-
_form_factor != XR_FORM_FACTOR_HANDHELD_DISPLAY) { \
316
-
\
317
-
return oxr_error(log, XR_ERROR_FORM_FACTOR_UNSUPPORTED, \
318
-
"(" #form_factor " == 0x%08x) is not a valid form factor", _form_factor); \
319
-
} \
320
-
} while (false)
321
-
322
#define OXR_VERIFY_HAND_TRACKING_DATA_SOURCE_OR_NULL(log, data_source_info) \
323
do { \
324
if (data_source_info != NULL) { \
···
333
do { \
334
if (OXR_FT->xft == NULL) { \
335
return oxr_error(LOG, XR_ERROR_FUTURE_INVALID_EXT, "future is not valid"); \
336
} \
337
} while (false)
338
···
408
struct oxr_instance *inst,
409
XrViewConfigurationType view_conf,
410
const char *view_conf_name);
411
412
XrResult
413
oxr_verify_XrSessionCreateInfo(struct oxr_logger * /*log*/,
···
1
// Copyright 2018-2024, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
23
struct oxr_action_set;
24
struct oxr_extension_status;
25
struct oxr_instance;
26
+
struct oxr_system;
27
struct oxr_logger;
28
struct oxr_subaction_paths;
29
···
97
#define OXR_VERIFY_FUTURE_AND_INIT_LOG(log, thing, new_thing, name) \
98
OXR_VERIFY_AND_SET_AND_INIT(log, thing, new_thing, oxr_future_ext, FUTURE, name, new_thing->inst); \
99
OXR_VERIFY_FUTURE_VALID(log, new_thing)
100
+
#define OXR_VERIFY_FACE_TRACKER_ANDROID_AND_INIT_LOG(log, thing, new_thing, name) \
101
+
OXR_VERIFY_AND_SET_AND_INIT(log, thing, new_thing, oxr_face_tracker_android, FTRACKER, name, new_thing->sess->sys->inst)
102
// clang-format on
103
104
#define OXR_VERIFY_INSTANCE_NOT_NULL(log, arg, new_arg) OXR_VERIFY_SET(log, arg, new_arg, oxr_instance, INSTANCE);
···
204
} \
205
} while (false)
206
207
+
#define OXR_VERIFY_TWO_CALL_ARRAY(log, inputCapacity, countOutput, array) \
208
+
do { \
209
+
OXR_VERIFY_ARG_NOT_NULL(log, countOutput); \
210
+
if (inputCapacity > 0) { \
211
+
OXR_VERIFY_ARG_NOT_NULL(log, array); \
212
+
} \
213
+
} while (false)
214
+
215
+
#define OXR_VERIFY_TWO_CALL_ARRAY_AND_TYPE(log, inputCapacity, countOutput, array, type_enum) \
216
+
do { \
217
+
OXR_VERIFY_ARG_NOT_NULL(log, countOutput); \
218
+
if (inputCapacity > 0) { \
219
+
OXR_VERIFY_ARG_NOT_NULL(log, array); \
220
+
for (uint32_t i = 0; i < inputCapacity; ++i) { \
221
+
OXR_VERIFY_ARG_ARRAY_ELEMENT_TYPE(log, array, i, type_enum); \
222
+
} \
223
+
} \
224
+
} while (false)
225
+
226
#define OXR_VERIFY_SUBACTION_PATHS(log, count, paths) \
227
do { \
228
if (count > 0 && paths == NULL) { \
···
255
\
256
if (!math_vec3_validate((struct xrt_vec3 *)&p.position)) { \
257
return oxr_error(log, XR_ERROR_POSE_INVALID, "(" #p ".position) is not valid"); \
258
+
} \
259
+
} while (false)
260
+
261
+
#define OXR_VERIFY_FORM_FACTOR(log, form_factor) \
262
+
do { \
263
+
XrFormFactor _form_factor = (form_factor); \
264
+
if (_form_factor != XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY && \
265
+
_form_factor != XR_FORM_FACTOR_HANDHELD_DISPLAY) { \
266
+
\
267
+
return oxr_error(log, XR_ERROR_FORM_FACTOR_UNSUPPORTED, \
268
+
"(" #form_factor " == 0x%08x) is not a valid form factor", _form_factor); \
269
} \
270
} while (false)
271
···
277
} \
278
} while (false)
279
280
+
#define OXR_VERIFY_VIEW_CONFIG_TYPE_SUPPORTED(log, sys, view_conf) \
281
+
do { \
282
+
XrResult verify_ret = oxr_verify_view_config_type_supported(log, sys, view_conf, #view_conf); \
283
+
if (verify_ret != XR_SUCCESS) { \
284
+
return verify_ret; \
285
+
} \
286
+
} while (false)
287
+
288
#define OXR_VERIFY_VIEW_INDEX(log, index) \
289
do { \
290
if (index > 2) { \
···
350
} \
351
} while (false)
352
353
#define OXR_VERIFY_HAND_TRACKING_DATA_SOURCE_OR_NULL(log, data_source_info) \
354
do { \
355
if (data_source_info != NULL) { \
···
364
do { \
365
if (OXR_FT->xft == NULL) { \
366
return oxr_error(LOG, XR_ERROR_FUTURE_INVALID_EXT, "future is not valid"); \
367
+
} \
368
+
} while (false)
369
+
370
+
#define OXR_VERIFY_ARG_TIME_NOT_ZERO(log, xr_time) \
371
+
do { \
372
+
if (xr_time <= (XrTime)0) { \
373
+
return oxr_error(log, XR_ERROR_TIME_INVALID, "(time == %" PRIi64 ") is not a valid time.", \
374
+
xr_time); \
375
} \
376
} while (false)
377
···
447
struct oxr_instance *inst,
448
XrViewConfigurationType view_conf,
449
const char *view_conf_name);
450
+
451
+
XrResult
452
+
oxr_verify_view_config_type_supported(struct oxr_logger *log,
453
+
struct oxr_system *sys,
454
+
XrViewConfigurationType view_conf,
455
+
const char *view_conf_name);
456
457
XrResult
458
oxr_verify_XrSessionCreateInfo(struct oxr_logger * /*log*/,
+23
-2
src/xrt/state_trackers/oxr/oxr_binding.c
+23
-2
src/xrt/state_trackers/oxr/oxr_binding.c
···
1
// Copyright 2018-2020,2023 Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
462
if (name == XRT_DEVICE_INVALID) {
463
return false;
464
}
465
/*
466
* Map xrt_device_name to an interaction profile XrPath.
467
-
* Set *out_p to an oxr_interaction_profile if bindings for that interaction profile XrPath have been suggested.
468
*/
469
for (uint32_t i = 0; i < ARRAY_SIZE(profile_templates); i++) {
470
if (name == profile_templates[i].name) {
471
-
if (interaction_profile_find_in_session(log, sess, profile_templates[i].path_cache, out_p)) {
472
return true;
473
}
474
}
···
1
// Copyright 2018-2020,2023 Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
463
if (name == XRT_DEVICE_INVALID) {
464
return false;
465
}
466
+
467
/*
468
* Map xrt_device_name to an interaction profile XrPath.
469
+
*
470
+
* There might be multiple OpenXR interaction profiles that maps to a
471
+
* a single @ref xrt_device_name, so we can't just grab the first one
472
+
* that we find and assume that wasn't bound then there isn't an OpenXR
473
+
* interaction profile bound for that device name. So we will need to
474
+
* keep looping until we find an OpenXR interaction profile, or we run
475
+
* out of interaction profiles that the app has suggested.
476
+
*
477
+
* For XRT_DEVICE_HAND_INTERACTION both the OpenXR hand-interaction
478
+
* profiles maps to it, but the app might only provide binding for one.
479
+
*
480
+
* Set *out_p to an oxr_interaction_profile if bindings for that
481
+
* interaction profile XrPath have been suggested.
482
*/
483
for (uint32_t i = 0; i < ARRAY_SIZE(profile_templates); i++) {
484
if (name == profile_templates[i].name) {
485
+
interaction_profile_find_in_session(log, sess, profile_templates[i].path_cache, out_p);
486
+
487
+
/*
488
+
* Keep looping even if the current matching OpenXR
489
+
* interaction profile wasn't suggested by the app.
490
+
* See comment above.
491
+
*/
492
+
if (*out_p != NULL) {
493
return true;
494
}
495
}
+77
src/xrt/state_trackers/oxr/oxr_conversions.h
+77
src/xrt/state_trackers/oxr/oxr_conversions.h
···
16
#include "xrt/xrt_vulkan_includes.h"
17
#include "xrt/xrt_openxr_includes.h"
18
19
+
#include "oxr_defines.h"
20
+
21
22
/*
23
*
···
291
default: assert(false); return XR_HAND_TRACKING_DATA_SOURCE_MAX_ENUM_EXT;
292
}
293
}
294
+
295
+
296
+
/*
297
+
*
298
+
* Basic types
299
+
*
300
+
*/
301
+
302
+
static inline XrExtent2Di
303
+
xrt_size_to_xr(const struct xrt_size *x)
304
+
{
305
+
return (XrExtent2Di){
306
+
.width = x->w,
307
+
.height = x->h,
308
+
};
309
+
}
310
+
311
+
static inline XrVector2f
312
+
xrt_vec2_to_xr(const struct xrt_vec2 *v)
313
+
{
314
+
return (XrVector2f){
315
+
.x = v->x,
316
+
.y = v->y,
317
+
};
318
+
}
319
+
320
+
static inline XrVector3f
321
+
xrt_vec3_to_xr(const struct xrt_vec3 *v)
322
+
{
323
+
return (XrVector3f){
324
+
.x = v->x,
325
+
.y = v->y,
326
+
.z = v->z,
327
+
};
328
+
}
329
+
330
+
static inline XrQuaternionf
331
+
xrt_quat_to_xr(const struct xrt_quat *q)
332
+
{
333
+
return (XrQuaternionf){
334
+
.x = q->x,
335
+
.y = q->y,
336
+
.z = q->z,
337
+
.w = q->w,
338
+
};
339
+
}
340
+
341
+
static inline XrPosef
342
+
xrt_pose_to_xr(const struct xrt_pose *q)
343
+
{
344
+
return (XrPosef){
345
+
.orientation = xrt_quat_to_xr(&q->orientation),
346
+
.position = xrt_vec3_to_xr(&q->position),
347
+
};
348
+
}
349
+
350
+
351
+
/*
352
+
*
353
+
* View things
354
+
*
355
+
*/
356
+
357
+
static inline XrViewConfigurationType
358
+
xrt_view_type_to_xr(enum xrt_view_type view_type)
359
+
{
360
+
switch (view_type) {
361
+
case XRT_VIEW_TYPE_MONO: return XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO;
362
+
case XRT_VIEW_TYPE_STEREO: return XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
363
+
}
364
+
365
+
// Used as default, to get warnings.
366
+
assert(false && "Invalid view type");
367
+
return XR_VIEW_CONFIGURATION_TYPE_MAX_ENUM;
368
+
}
+18
-18
src/xrt/state_trackers/oxr/oxr_defines.h
+18
-18
src/xrt/state_trackers/oxr/oxr_defines.h
···
15
16
// For corruption and layer checking.
17
// clang-format off
18
-
#define OXR_XR_DEBUG_INSTANCE (*(uint64_t *)"oxrinst\0")
19
-
#define OXR_XR_DEBUG_SESSION (*(uint64_t *)"oxrsess\0")
20
-
#define OXR_XR_DEBUG_SPACE (*(uint64_t *)"oxrspac\0")
21
-
#define OXR_XR_DEBUG_PATH (*(uint64_t *)"oxrpath\0")
22
-
#define OXR_XR_DEBUG_ACTION (*(uint64_t *)"oxracti\0")
23
-
#define OXR_XR_DEBUG_SWAPCHAIN (*(uint64_t *)"oxrswap\0")
24
-
#define OXR_XR_DEBUG_ACTIONSET (*(uint64_t *)"oxraset\0")
25
-
#define OXR_XR_DEBUG_MESSENGER (*(uint64_t *)"oxrmess\0")
26
-
#define OXR_XR_DEBUG_SOURCESET (*(uint64_t *)"oxrsrcs\0")
27
-
#define OXR_XR_DEBUG_SOURCE (*(uint64_t *)"oxrsrc_\0")
28
-
#define OXR_XR_DEBUG_HTRACKER (*(uint64_t *)"oxrhtra\0")
29
-
#define OXR_XR_DEBUG_PASSTHROUGH (*(uint64_t *)"oxrpass\0")
30
-
#define OXR_XR_DEBUG_PASSTHROUGH_LAYER (*(uint64_t *)"oxrptla\0")
31
-
#define OXR_XR_DEBUG_FTRACKER (*(uint64_t *)"oxrftra\0")
32
// body tracker
33
-
#define OXR_XR_DEBUG_BTRACKER (*(uint64_t *)"oxrbtra\0")
34
-
#define OXR_XR_DEBUG_XDEVLIST (*(uint64_t *)"oxrxdli\0")
35
// plane detection
36
-
#define OXR_XR_DEBUG_PLANEDET (*(uint64_t *)"oxrplan\0")
37
// futures
38
-
#define OXR_XR_DEBUG_FUTURE (*(uint64_t *)"oxrfutr\0")
39
// clang-format on
40
41
/*!
···
15
16
// For corruption and layer checking.
17
// clang-format off
18
+
#define OXR_XR_DEBUG_INSTANCE (*(uint64_t *)"oxrinst\0")
19
+
#define OXR_XR_DEBUG_SESSION (*(uint64_t *)"oxrsess\0")
20
+
#define OXR_XR_DEBUG_SPACE (*(uint64_t *)"oxrspac\0")
21
+
#define OXR_XR_DEBUG_PATH (*(uint64_t *)"oxrpath\0")
22
+
#define OXR_XR_DEBUG_ACTION (*(uint64_t *)"oxracti\0")
23
+
#define OXR_XR_DEBUG_SWAPCHAIN (*(uint64_t *)"oxrswap\0")
24
+
#define OXR_XR_DEBUG_ACTIONSET (*(uint64_t *)"oxraset\0")
25
+
#define OXR_XR_DEBUG_MESSENGER (*(uint64_t *)"oxrmess\0")
26
+
#define OXR_XR_DEBUG_SOURCESET (*(uint64_t *)"oxrsrcs\0")
27
+
#define OXR_XR_DEBUG_SOURCE (*(uint64_t *)"oxrsrc_\0")
28
+
#define OXR_XR_DEBUG_HTRACKER (*(uint64_t *)"oxrhtra\0")
29
+
#define OXR_XR_DEBUG_PASSTHROUGH (*(uint64_t *)"oxrpass\0")
30
+
#define OXR_XR_DEBUG_PASSTHROUGH_LAYER (*(uint64_t *)"oxrptla\0")
31
+
#define OXR_XR_DEBUG_FTRACKER (*(uint64_t *)"oxrftra\0")
32
// body tracker
33
+
#define OXR_XR_DEBUG_BTRACKER (*(uint64_t *)"oxrbtra\0")
34
+
#define OXR_XR_DEBUG_XDEVLIST (*(uint64_t *)"oxrxdli\0")
35
// plane detection
36
+
#define OXR_XR_DEBUG_PLANEDET (*(uint64_t *)"oxrplan\0")
37
// futures
38
+
#define OXR_XR_DEBUG_FUTURE (*(uint64_t *)"oxrfutr\0")
39
// clang-format on
40
41
/*!
+24
-12
src/xrt/state_trackers/oxr/oxr_extension_support.h
+24
-12
src/xrt/state_trackers/oxr/oxr_extension_support.h
···
475
476
477
/*
478
* XR_BD_controller_interaction
479
*/
480
#if defined(XR_BD_controller_interaction) && defined(XRT_FEATURE_OPENXR_INTERACTION_BYTEDANCE)
···
797
798
799
/*
800
-
* XR_MNDX_oculus_remote
801
-
*/
802
-
#if defined(XR_MNDX_oculus_remote) && defined(XRT_FEATURE_OPENXR_INTERACTION_MNDX)
803
-
#define OXR_HAVE_MNDX_oculus_remote
804
-
#define OXR_EXTENSION_SUPPORT_MNDX_oculus_remote(_) _(MNDX_oculus_remote, MNDX_OCULUS_REMOTE)
805
-
#else
806
-
#define OXR_EXTENSION_SUPPORT_MNDX_oculus_remote(_)
807
-
#endif
808
-
809
-
810
-
/*
811
* XR_MNDX_egl_enable
812
*/
813
#if defined(XR_MNDX_egl_enable) && defined(XR_USE_PLATFORM_EGL)
···
837
#define OXR_EXTENSION_SUPPORT_MNDX_hydra(_) _(MNDX_hydra, MNDX_HYDRA)
838
#else
839
#define OXR_EXTENSION_SUPPORT_MNDX_hydra(_)
840
#endif
841
842
···
936
OXR_EXTENSION_SUPPORT_EXT_plane_detection(_) \
937
OXR_EXTENSION_SUPPORT_EXT_samsung_odyssey_controller(_) \
938
OXR_EXTENSION_SUPPORT_EXT_user_presence(_) \
939
OXR_EXTENSION_SUPPORT_BD_controller_interaction(_) \
940
OXR_EXTENSION_SUPPORT_FB_body_tracking(_) \
941
OXR_EXTENSION_SUPPORT_FB_composition_layer_alpha_blend(_) \
···
964
OXR_EXTENSION_SUPPORT_HTCX_vive_tracker_interaction(_) \
965
OXR_EXTENSION_SUPPORT_MNDX_ball_on_a_stick_controller(_) \
966
OXR_EXTENSION_SUPPORT_MNDX_blubur_s1(_) \
967
-
OXR_EXTENSION_SUPPORT_MNDX_oculus_remote(_) \
968
OXR_EXTENSION_SUPPORT_MNDX_egl_enable(_) \
969
OXR_EXTENSION_SUPPORT_MNDX_force_feedback_curl(_) \
970
OXR_EXTENSION_SUPPORT_MNDX_hydra(_) \
971
OXR_EXTENSION_SUPPORT_MNDX_psvr2_interaction(_) \
972
OXR_EXTENSION_SUPPORT_MNDX_system_buttons(_) \
973
OXR_EXTENSION_SUPPORT_MNDX_xdev_space(_)
···
475
476
477
/*
478
+
* XR_ANDROID_face_tracking
479
+
*/
480
+
#if defined(XR_ANDROID_face_tracking) && defined(XRT_FEATURE_OPENXR_FACE_TRACKING_ANDROID)
481
+
#define OXR_HAVE_ANDROID_face_tracking
482
+
#define OXR_EXTENSION_SUPPORT_ANDROID_face_tracking(_) _(ANDROID_face_tracking, ANDROID_FACE_TRACKING)
483
+
#else
484
+
#define OXR_EXTENSION_SUPPORT_ANDROID_face_tracking(_)
485
+
#endif
486
+
487
+
488
+
/*
489
* XR_BD_controller_interaction
490
*/
491
#if defined(XR_BD_controller_interaction) && defined(XRT_FEATURE_OPENXR_INTERACTION_BYTEDANCE)
···
808
809
810
/*
811
* XR_MNDX_egl_enable
812
*/
813
#if defined(XR_MNDX_egl_enable) && defined(XR_USE_PLATFORM_EGL)
···
837
#define OXR_EXTENSION_SUPPORT_MNDX_hydra(_) _(MNDX_hydra, MNDX_HYDRA)
838
#else
839
#define OXR_EXTENSION_SUPPORT_MNDX_hydra(_)
840
+
#endif
841
+
842
+
843
+
/*
844
+
* XR_MNDX_oculus_remote
845
+
*/
846
+
#if defined(XR_MNDX_oculus_remote) && defined(XRT_FEATURE_OPENXR_INTERACTION_MNDX)
847
+
#define OXR_HAVE_MNDX_oculus_remote
848
+
#define OXR_EXTENSION_SUPPORT_MNDX_oculus_remote(_) _(MNDX_oculus_remote, MNDX_OCULUS_REMOTE)
849
+
#else
850
+
#define OXR_EXTENSION_SUPPORT_MNDX_oculus_remote(_)
851
#endif
852
853
···
947
OXR_EXTENSION_SUPPORT_EXT_plane_detection(_) \
948
OXR_EXTENSION_SUPPORT_EXT_samsung_odyssey_controller(_) \
949
OXR_EXTENSION_SUPPORT_EXT_user_presence(_) \
950
+
OXR_EXTENSION_SUPPORT_ANDROID_face_tracking(_) \
951
OXR_EXTENSION_SUPPORT_BD_controller_interaction(_) \
952
OXR_EXTENSION_SUPPORT_FB_body_tracking(_) \
953
OXR_EXTENSION_SUPPORT_FB_composition_layer_alpha_blend(_) \
···
976
OXR_EXTENSION_SUPPORT_HTCX_vive_tracker_interaction(_) \
977
OXR_EXTENSION_SUPPORT_MNDX_ball_on_a_stick_controller(_) \
978
OXR_EXTENSION_SUPPORT_MNDX_blubur_s1(_) \
979
OXR_EXTENSION_SUPPORT_MNDX_egl_enable(_) \
980
OXR_EXTENSION_SUPPORT_MNDX_force_feedback_curl(_) \
981
OXR_EXTENSION_SUPPORT_MNDX_hydra(_) \
982
+
OXR_EXTENSION_SUPPORT_MNDX_oculus_remote(_) \
983
OXR_EXTENSION_SUPPORT_MNDX_psvr2_interaction(_) \
984
OXR_EXTENSION_SUPPORT_MNDX_system_buttons(_) \
985
OXR_EXTENSION_SUPPORT_MNDX_xdev_space(_)
-119
src/xrt/state_trackers/oxr/oxr_face_tracking.c
-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
+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
+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
+99
-32
src/xrt/state_trackers/oxr/oxr_input.c
···
1
// Copyright 2018-2024, Collabora, Ltd.
2
-
// Copyright 2023, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
9
* @ingroup oxr_main
10
*/
11
12
-
#include "b_generated_bindings_helpers.h"
13
#include "oxr_bindings/b_oxr_generated_bindings.h"
14
#include "util/u_debug.h"
15
#include "util/u_time.h"
···
515
*/
516
517
static bool
518
do_inputs(struct oxr_binding *binding_point,
519
struct xrt_device *xdev,
520
struct xrt_binding_profile *xbp,
···
523
uint32_t *input_count)
524
{
525
enum xrt_input_name name = 0;
526
-
if (xbp == NULL) {
527
-
name = binding_point->input;
528
-
} else {
529
-
for (size_t i = 0; i < xbp->input_count; i++) {
530
-
if (binding_point->input != xbp->inputs[i].from) {
531
-
continue;
532
-
}
533
534
-
// We have found a device mapping.
535
-
name = xbp->inputs[i].device;
536
-
break;
537
-
}
538
539
-
// Didn't find a mapping.
540
-
if (name == 0) {
541
return false;
542
}
543
}
544
545
struct xrt_input *input = NULL;
546
-
if (oxr_xdev_find_input(xdev, name, &input)) {
547
-
uint32_t index = (*input_count)++;
548
-
inputs[index].input = input;
549
-
inputs[index].xdev = xdev;
550
-
inputs[index].bound_path = matched_path;
551
-
if (binding_point->dpad_activate != 0) {
552
-
struct xrt_input *dpad_activate = NULL;
553
-
if (!oxr_xdev_find_input(xdev, binding_point->dpad_activate, &dpad_activate)) {
554
-
return false;
555
-
}
556
-
inputs[index].dpad_activate_name = binding_point->dpad_activate;
557
-
inputs[index].dpad_activate = dpad_activate;
558
}
559
-
return true;
560
}
561
562
-
return false;
563
}
564
565
static bool
···
771
if (found) {
772
if (xbp == NULL) {
773
oxr_slog(slog, "\t\t\t\tBound (xdev '%s'): %s!\n", xdev->str,
774
-
xrt_input_name_string(binding_points[i]->input));
775
} else {
776
oxr_slog(slog, "\t\t\t\tBound (xbp)!\n");
777
}
···
1626
// Only add the input if we can find a transform.
1627
1628
oxr_slog(slog, "\t\tFinding transforms for '%s' to action '%s' of type '%s'\n",
1629
-
xrt_input_name_string(inputs[i].input->name), act_ref->name,
1630
xr_action_type_to_str(act_ref->action_type));
1631
1632
enum oxr_dpad_region dpad_region;
···
1667
struct xrt_input *input = cache->inputs[i].input;
1668
enum xrt_input_type t = XRT_GET_INPUT_TYPE(input->name);
1669
bool active = input->active;
1670
-
oxr_slog(slog, "\t\t\t'%s' ('%s') on '%s' (%s)\n", xrt_input_name_string(input->name),
1671
xrt_input_type_to_str(t), cache->inputs[i].xdev->str,
1672
active ? "active" : "inactive");
1673
}
···
1862
struct oxr_action_set *act_set = NULL;
1863
struct oxr_action_set_attachment *act_set_attached = NULL;
1864
1865
// Check that all action sets has been attached.
1866
for (uint32_t i = 0; i < countActionSets; i++) {
1867
oxr_session_get_action_set_attachment(sess, actionSets[i].actionSet, &act_set_attached, &act_set);
···
1871
"not been attached to this session",
1872
i, act_set != NULL ? act_set->data->name : "NULL");
1873
}
1874
}
1875
1876
// Synchronize outputs to this time.
···
1922
OXR_FOR_EACH_SUBACTION_PATH(ACCUMULATE_REQUESTED)
1923
#undef ACCUMULATE_REQUESTED
1924
}
1925
if (!any_action_with_subactionpath) {
1926
return oxr_error(log, XR_ERROR_PATH_UNSUPPORTED,
1927
"No action with specified subactionpath in actionset");
···
1
// Copyright 2018-2024, Collabora, Ltd.
2
+
// Copyright 2023-2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
9
* @ingroup oxr_main
10
*/
11
12
#include "oxr_bindings/b_oxr_generated_bindings.h"
13
#include "util/u_debug.h"
14
#include "util/u_time.h"
···
514
*/
515
516
static bool
517
+
find_xdev_name_from_pairs(const struct xrt_device *xdev,
518
+
const struct xrt_binding_profile *xbp,
519
+
enum xrt_input_name from_name,
520
+
enum xrt_input_name *out_name)
521
+
{
522
+
if (from_name == 0) {
523
+
*out_name = 0;
524
+
return true; // Not asking for anything, just keep going.
525
+
}
526
+
527
+
/*
528
+
* For asymmetrical devices like PS Sense being re-bound to a symmetrical
529
+
* "device" like simple controller can be problemantic as depending on
530
+
* which hand it is menu is bound to different inputs. Instead of making
531
+
* the driver have two completely unique binding mappings per hand, we
532
+
* instead loop over all pairs finding the first match. In other words
533
+
* this means there can be multiple of the same 'from' value in the
534
+
* array of input pairs.
535
+
*/
536
+
for (size_t i = 0; i < xbp->input_count; i++) {
537
+
if (from_name != xbp->inputs[i].from) {
538
+
continue;
539
+
}
540
+
541
+
// What is the name on the xdev?
542
+
enum xrt_input_name xdev_name = xbp->inputs[i].device;
543
+
544
+
// See if we can't find it.
545
+
for (uint32_t k = 0; k < xdev->input_count; k++) {
546
+
if (xdev->inputs[k].name == xdev_name) {
547
+
*out_name = xdev_name;
548
+
return true;
549
+
}
550
+
}
551
+
}
552
+
553
+
return false;
554
+
}
555
+
556
+
static bool
557
do_inputs(struct oxr_binding *binding_point,
558
struct xrt_device *xdev,
559
struct xrt_binding_profile *xbp,
···
562
uint32_t *input_count)
563
{
564
enum xrt_input_name name = 0;
565
+
enum xrt_input_name dpad_activate_name = 0;
566
567
+
if (xbp != NULL) {
568
+
bool t1 = find_xdev_name_from_pairs(xdev, xbp, binding_point->input, &name);
569
+
bool t2 = find_xdev_name_from_pairs(xdev, xbp, binding_point->dpad_activate, &dpad_activate_name);
570
571
+
// We couldn't find the needed inputs on the device.
572
+
if (!t1 || !t2) {
573
return false;
574
}
575
+
} else {
576
+
name = binding_point->input;
577
+
dpad_activate_name = binding_point->dpad_activate;
578
}
579
580
struct xrt_input *input = NULL;
581
+
struct xrt_input *dpad_activate_input = NULL;
582
+
583
+
// Early out if there is no such input.
584
+
if (!oxr_xdev_find_input(xdev, name, &input)) {
585
+
return false;
586
+
}
587
+
588
+
// Check this before allocating an input.
589
+
if (dpad_activate_name != 0) {
590
+
if (!oxr_xdev_find_input(xdev, dpad_activate_name, &dpad_activate_input)) {
591
+
return false;
592
}
593
+
}
594
+
595
+
uint32_t index = (*input_count)++;
596
+
inputs[index].input = input;
597
+
inputs[index].xdev = xdev;
598
+
inputs[index].bound_path = matched_path;
599
+
if (dpad_activate_input != NULL) {
600
+
inputs[index].dpad_activate_name = dpad_activate_name;
601
+
inputs[index].dpad_activate = dpad_activate_input;
602
}
603
604
+
return true;
605
}
606
607
static bool
···
813
if (found) {
814
if (xbp == NULL) {
815
oxr_slog(slog, "\t\t\t\tBound (xdev '%s'): %s!\n", xdev->str,
816
+
u_str_xrt_input_name(binding_points[i]->input));
817
} else {
818
oxr_slog(slog, "\t\t\t\tBound (xbp)!\n");
819
}
···
1668
// Only add the input if we can find a transform.
1669
1670
oxr_slog(slog, "\t\tFinding transforms for '%s' to action '%s' of type '%s'\n",
1671
+
u_str_xrt_input_name(inputs[i].input->name), act_ref->name,
1672
xr_action_type_to_str(act_ref->action_type));
1673
1674
enum oxr_dpad_region dpad_region;
···
1709
struct xrt_input *input = cache->inputs[i].input;
1710
enum xrt_input_type t = XRT_GET_INPUT_TYPE(input->name);
1711
bool active = input->active;
1712
+
oxr_slog(slog, "\t\t\t'%s' ('%s') on '%s' (%s)\n", u_str_xrt_input_name(input->name),
1713
xrt_input_type_to_str(t), cache->inputs[i].xdev->str,
1714
active ? "active" : "inactive");
1715
}
···
1904
struct oxr_action_set *act_set = NULL;
1905
struct oxr_action_set_attachment *act_set_attached = NULL;
1906
1907
+
/*
1908
+
* No side-effects allowed in this section as we are still
1909
+
* validating and checking for errors at this point.
1910
+
*/
1911
+
1912
// Check that all action sets has been attached.
1913
for (uint32_t i = 0; i < countActionSets; i++) {
1914
oxr_session_get_action_set_attachment(sess, actionSets[i].actionSet, &act_set_attached, &act_set);
···
1918
"not been attached to this session",
1919
i, act_set != NULL ? act_set->data->name : "NULL");
1920
}
1921
+
}
1922
+
1923
+
/*
1924
+
* Can only call this function if the session state is focused. This is
1925
+
* not an error and has to be checked after all validation, but before
1926
+
* any side-effects happens.
1927
+
*/
1928
+
if (sess->state != XR_SESSION_STATE_FOCUSED) {
1929
+
return XR_SESSION_NOT_FOCUSED;
1930
+
}
1931
+
1932
+
/*
1933
+
* Side-effects allowed below, but not validation.
1934
+
*/
1935
+
1936
+
if (countActionSets == 0) {
1937
+
// Nothing to do.
1938
+
return XR_SUCCESS;
1939
}
1940
1941
// Synchronize outputs to this time.
···
1987
OXR_FOR_EACH_SUBACTION_PATH(ACCUMULATE_REQUESTED)
1988
#undef ACCUMULATE_REQUESTED
1989
}
1990
+
1991
+
//! @TODO This validation is not allowed here, must done above.
1992
if (!any_action_with_subactionpath) {
1993
return oxr_error(log, XR_ERROR_PATH_UNSUPPORTED,
1994
"No action with specified subactionpath in actionset");
+96
-54
src/xrt/state_trackers/oxr/oxr_instance.c
+96
-54
src/xrt/state_trackers/oxr/oxr_instance.c
···
91
inst->system.visibility_mask[i] = NULL;
92
}
93
94
xrt_space_overseer_destroy(&inst->system.xso);
95
os_mutex_destroy(&inst->system.sync_actions_mutex);
96
xrt_system_devices_destroy(&inst->system.xsysd);
···
199
{
200
// Reset.
201
inst->quirks.skip_end_session = false;
202
inst->quirks.disable_vulkan_format_depth_stencil = false;
203
inst->quirks.no_validation_error_in_create_ref_space = false;
204
···
256
ret = oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to init sync action mutex");
257
return ret;
258
}
259
260
#ifdef XRT_FEATURE_CLIENT_DEBUG_GUI
261
struct u_debug_gui_create_info udgci = {
···
331
#ifdef OXR_HAVE_META_body_tracking_calibration
332
.meta_body_tracking_calibration_enabled = extensions->META_body_tracking_calibration,
333
#endif
334
};
335
snprintf(i_info.app_info.application_name, sizeof(i_info.app_info.application_name), "%s",
336
createInfo->applicationInfo.applicationName);
···
370
}
371
#endif // XRT_OS_ANDROID
372
373
-
struct oxr_system *sys = &inst->system;
374
-
375
-
// Create the compositor if we are not headless, currently always create it.
376
-
bool should_create_compositor = true /* !inst->extensions.MND_headless */;
377
-
378
-
// Create the system.
379
-
if (should_create_compositor) {
380
-
xret = xrt_instance_create_system(inst->xinst, &sys->xsys, &sys->xsysd, &sys->xso, &sys->xsysc);
381
-
} else {
382
-
xret = xrt_instance_create_system(inst->xinst, &sys->xsys, &sys->xsysd, &sys->xso, NULL);
383
-
}
384
-
385
-
if (xret != XRT_SUCCESS) {
386
-
ret = oxr_error(log, XR_ERROR_INITIALIZATION_FAILED, "Failed to create the system '%i'", xret);
387
-
oxr_instance_destroy(log, &inst->handle);
388
-
return ret;
389
-
}
390
-
391
-
ret = XR_SUCCESS;
392
-
if (sys->xsysd == NULL) {
393
-
ret = oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Huh?! Field sys->xsysd was NULL?");
394
-
} else if (should_create_compositor && sys->xsysc == NULL) {
395
-
ret = oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Huh?! Field sys->xsysc was NULL?");
396
-
} else if (!should_create_compositor && sys->xsysc != NULL) {
397
-
ret = oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Huh?! Field sys->xsysc was not NULL?");
398
-
}
399
-
400
-
if (ret != XR_SUCCESS) {
401
-
oxr_instance_destroy(log, &inst->handle);
402
-
return ret;
403
-
}
404
-
405
-
// Did we find any HMD
406
-
// @todo Headless with only controllers?
407
-
struct xrt_device *dev = GET_XDEV_BY_ROLE(sys, head);
408
-
if (dev == NULL) {
409
-
ret = oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to find any HMD device");
410
-
oxr_instance_destroy(log, &inst->handle);
411
-
return ret;
412
-
}
413
-
uint32_t view_count = dev->hmd->view_count;
414
-
ret = oxr_system_fill_in(log, inst, XRT_SYSTEM_ID, view_count, &inst->system);
415
-
if (ret != XR_SUCCESS) {
416
-
oxr_instance_destroy(log, &inst->handle);
417
-
return ret;
418
-
}
419
-
420
inst->timekeeping = time_state_create(inst->xinst->startup_timestamp);
421
422
//! @todo check if this (and other creates) failed?
···
429
430
u_var_add_root((void *)inst, "XrInstance", true);
431
432
-
#ifdef XRT_FEATURE_CLIENT_DEBUG_GUI
433
-
u_debug_gui_start(inst->debug_ui, inst->xinst, sys->xsysd);
434
-
#endif
435
-
436
oxr_log(log,
437
"Instance created\n"
438
"\tcreateInfo->applicationInfo.applicationName: %s\n"
···
442
"\tcreateInfo->applicationInfo.apiVersion: %d.%d.%d\n"
443
"\tappinfo.detected.engine.name: %s\n"
444
"\tappinfo.detected.engine.version: %i.%i.%i\n"
445
"\tquirks.disable_vulkan_format_depth_stencil: %s\n"
446
"\tquirks.no_validation_error_in_create_ref_space: %s\n"
447
"\tquirks.skip_end_session: %s\n"
···
457
inst->appinfo.detected.engine.major, //
458
inst->appinfo.detected.engine.minor, //
459
inst->appinfo.detected.engine.patch, //
460
inst->quirks.disable_vulkan_format_depth_stencil ? "true" : "false", //
461
inst->quirks.no_validation_error_in_create_ref_space ? "true" : "false", //
462
inst->quirks.skip_end_session ? "true" : "false", //
463
inst->quirks.parallel_views ? "true" : "false" //
464
); //
465
466
-
debug_print_devices(log, sys);
467
-
468
-
469
#ifdef XRT_FEATURE_RENDERDOC
470
471
#ifdef __GNUC__
···
506
#endif
507
508
*out_instance = inst;
509
510
return XR_SUCCESS;
511
}
···
91
inst->system.visibility_mask[i] = NULL;
92
}
93
94
+
os_mutex_destroy(&inst->system_init_lock);
95
+
96
xrt_space_overseer_destroy(&inst->system.xso);
97
os_mutex_destroy(&inst->system.sync_actions_mutex);
98
xrt_system_devices_destroy(&inst->system.xsysd);
···
201
{
202
// Reset.
203
inst->quirks.skip_end_session = false;
204
+
inst->quirks.disable_vulkan_format_depth = false;
205
inst->quirks.disable_vulkan_format_depth_stencil = false;
206
inst->quirks.no_validation_error_in_create_ref_space = false;
207
···
259
ret = oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to init sync action mutex");
260
return ret;
261
}
262
+
263
+
m_ret = os_mutex_init(&inst->system_init_lock);
264
+
if (m_ret < 0) {
265
+
ret = oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to init system init mutex");
266
+
return ret;
267
+
}
268
+
269
270
#ifdef XRT_FEATURE_CLIENT_DEBUG_GUI
271
struct u_debug_gui_create_info udgci = {
···
341
#ifdef OXR_HAVE_META_body_tracking_calibration
342
.meta_body_tracking_calibration_enabled = extensions->META_body_tracking_calibration,
343
#endif
344
+
#ifdef OXR_HAVE_ANDROID_face_tracking
345
+
.android_face_tracking_enabled = extensions->ANDROID_face_tracking,
346
+
#endif
347
};
348
snprintf(i_info.app_info.application_name, sizeof(i_info.app_info.application_name), "%s",
349
createInfo->applicationInfo.applicationName);
···
383
}
384
#endif // XRT_OS_ANDROID
385
386
inst->timekeeping = time_state_create(inst->xinst->startup_timestamp);
387
388
//! @todo check if this (and other creates) failed?
···
395
396
u_var_add_root((void *)inst, "XrInstance", true);
397
398
oxr_log(log,
399
"Instance created\n"
400
"\tcreateInfo->applicationInfo.applicationName: %s\n"
···
404
"\tcreateInfo->applicationInfo.apiVersion: %d.%d.%d\n"
405
"\tappinfo.detected.engine.name: %s\n"
406
"\tappinfo.detected.engine.version: %i.%i.%i\n"
407
+
"\tquirks.disable_vulkan_format_depth: %s\n"
408
"\tquirks.disable_vulkan_format_depth_stencil: %s\n"
409
"\tquirks.no_validation_error_in_create_ref_space: %s\n"
410
"\tquirks.skip_end_session: %s\n"
···
420
inst->appinfo.detected.engine.major, //
421
inst->appinfo.detected.engine.minor, //
422
inst->appinfo.detected.engine.patch, //
423
+
inst->quirks.disable_vulkan_format_depth ? "true" : "false", //
424
inst->quirks.disable_vulkan_format_depth_stencil ? "true" : "false", //
425
inst->quirks.no_validation_error_in_create_ref_space ? "true" : "false", //
426
inst->quirks.skip_end_session ? "true" : "false", //
427
inst->quirks.parallel_views ? "true" : "false" //
428
); //
429
430
#ifdef XRT_FEATURE_RENDERDOC
431
432
#ifdef __GNUC__
···
467
#endif
468
469
*out_instance = inst;
470
+
471
+
return XR_SUCCESS;
472
+
}
473
+
474
+
XrResult
475
+
oxr_instance_init_system_locked(struct oxr_logger *log, struct oxr_instance *inst)
476
+
{
477
+
struct oxr_system *sys = &inst->system;
478
+
if (sys->xsys) {
479
+
return XR_SUCCESS;
480
+
}
481
+
482
+
xrt_result_t xret;
483
+
XrResult ret;
484
+
485
+
bool available = false;
486
+
xret = xrt_instance_is_system_available(inst->xinst, &available);
487
+
if (xret != XRT_SUCCESS) {
488
+
struct u_pp_sink_stack_only sink;
489
+
u_pp_delegate_t dg = u_pp_sink_stack_only_init(&sink);
490
+
u_pp(dg, "Call to xrt_instance_is_system_available failed: ");
491
+
u_pp_xrt_result(dg, xret);
492
+
ret = oxr_error(log, xret == XRT_ERROR_IPC_FAILURE ? XR_ERROR_INSTANCE_LOST : XR_ERROR_RUNTIME_FAILURE,
493
+
"%s", sink.buffer);
494
+
return ret;
495
+
}
496
+
if (!available) {
497
+
return XR_ERROR_FORM_FACTOR_UNAVAILABLE;
498
+
}
499
+
500
+
// Create the compositor if we are not headless, currently always create it.
501
+
bool should_create_compositor = true /* !inst->extensions.MND_headless */;
502
+
503
+
// Create the system.
504
+
if (should_create_compositor) {
505
+
xret = xrt_instance_create_system(inst->xinst, &sys->xsys, &sys->xsysd, &sys->xso, &sys->xsysc);
506
+
} else {
507
+
xret = xrt_instance_create_system(inst->xinst, &sys->xsys, &sys->xsysd, &sys->xso, NULL);
508
+
}
509
+
510
+
if (xret != XRT_SUCCESS) {
511
+
struct u_pp_sink_stack_only sink;
512
+
u_pp_delegate_t dg = u_pp_sink_stack_only_init(&sink);
513
+
u_pp(dg, "Call to xrt_instance_create_system failed: ");
514
+
u_pp_xrt_result(dg, xret);
515
+
ret = oxr_error(log, XR_ERROR_INITIALIZATION_FAILED, "%s", sink.buffer);
516
+
return ret;
517
+
}
518
+
519
+
#ifdef XRT_FEATURE_CLIENT_DEBUG_GUI
520
+
// Do this after creating the system.
521
+
u_debug_gui_start(inst->debug_ui, inst->xinst, sys->xsysd);
522
+
#endif
523
+
524
+
ret = XR_SUCCESS;
525
+
if (sys->xsysd == NULL) {
526
+
ret = oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Huh?! Field sys->xsysd was NULL?");
527
+
} else if (should_create_compositor && sys->xsysc == NULL) {
528
+
ret = oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Huh?! Field sys->xsysc was NULL?");
529
+
} else if (!should_create_compositor && sys->xsysc != NULL) {
530
+
ret = oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Huh?! Field sys->xsysc was not NULL?");
531
+
}
532
+
533
+
if (ret != XR_SUCCESS) {
534
+
return ret;
535
+
}
536
+
537
+
// Did we find any HMD
538
+
// @todo Headless with only controllers?
539
+
struct xrt_device *dev = GET_XDEV_BY_ROLE(sys, head);
540
+
if (dev == NULL) {
541
+
ret = oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to find any HMD device");
542
+
return ret;
543
+
}
544
+
uint32_t view_count = (uint32_t)dev->hmd->view_count;
545
+
ret = oxr_system_fill_in(log, inst, XRT_SYSTEM_ID, view_count, &inst->system);
546
+
if (ret != XR_SUCCESS) {
547
+
return ret;
548
+
}
549
+
550
+
debug_print_devices(log, sys);
551
552
return XR_SUCCESS;
553
}
+134
-6
src/xrt/state_trackers/oxr/oxr_objects.h
+134
-6
src/xrt/state_trackers/oxr/oxr_objects.h
···
1
// Copyright 2018-2024, Collabora, Ltd.
2
-
// Copyright 2023, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
127
struct oxr_action_set_ref;
128
struct oxr_action_ref;
129
struct oxr_hand_tracker;
130
struct oxr_facial_tracker_htc;
131
struct oxr_face_tracker2_fb;
132
struct oxr_body_tracker_fb;
···
252
struct oxr_instance **out_inst);
253
254
/*!
255
* @public @memberof oxr_instance
256
*/
257
XrResult
···
459
return XRT_CAST_PTR_TO_OXR_HANDLE(XrFaceTracker2FB, face_tracker2_fb);
460
}
461
#endif
462
/*!
463
*
464
* @name oxr_input.c
···
976
XrTime time,
977
struct xrt_space_relation *out_relation);
978
979
980
/*
981
*
···
1086
1087
bool
1088
oxr_system_get_force_feedback_support(struct oxr_logger *log, struct oxr_instance *inst);
1089
1090
void
1091
oxr_system_get_face_tracking_htc_support(struct oxr_logger *log,
···
1474
};
1475
1476
/*!
1477
* Single or multiple devices grouped together to form a system that sessions
1478
* can be created from. Might need to open devices to get all
1479
* properties from it, but shouldn't.
···
1505
//! Have the client application called the gfx api requirements func?
1506
bool gotten_requirements;
1507
1508
-
XrViewConfigurationType view_config_type;
1509
-
XrViewConfigurationView views[2];
1510
-
uint32_t blend_mode_count;
1511
-
XrEnvironmentBlendMode blend_modes[3];
1512
1513
XrReferenceSpaceType reference_spaces[5];
1514
uint32_t reference_space_count;
···
1529
//! The device returned with the last xrGetVulkanGraphicsDeviceKHR or xrGetVulkanGraphicsDevice2KHR call.
1530
//! XR_NULL_HANDLE if neither has been called.
1531
VkPhysicalDevice suggested_vulkan_physical_device;
1532
1533
struct
1534
{
···
1689
XrVersion major_minor;
1690
} openxr_version;
1691
1692
// Hardcoded single system.
1693
struct oxr_system system;
1694
···
1748
1749
struct
1750
{
1751
-
//! Unreal has a bug in the VulkanRHI backend.
1752
bool disable_vulkan_format_depth_stencil;
1753
//! Unreal 4 has a bug calling xrEndSession; the function should just exit
1754
bool skip_end_session;
1755
···
1811
struct oxr_session *next;
1812
1813
XrSessionState state;
1814
1815
/*!
1816
* There is a extra state between xrBeginSession has been called and
···
3023
XrResult
3024
oxr_event_push_XrEventDataUserPresenceChangedEXT(struct oxr_logger *log, struct oxr_session *sess, bool isUserPresent);
3025
#endif // OXR_HAVE_EXT_user_presence
3026
3027
/*!
3028
* @}
···
1
// Copyright 2018-2024, Collabora, Ltd.
2
+
// Copyright 2023-2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
127
struct oxr_action_set_ref;
128
struct oxr_action_ref;
129
struct oxr_hand_tracker;
130
+
struct oxr_face_tracker_android;
131
struct oxr_facial_tracker_htc;
132
struct oxr_face_tracker2_fb;
133
struct oxr_body_tracker_fb;
···
253
struct oxr_instance **out_inst);
254
255
/*!
256
+
* Must be called with oxr_instance::system_init_lock held.
257
+
*
258
+
* @public @memberof oxr_instance
259
+
*/
260
+
XrResult
261
+
oxr_instance_init_system_locked(struct oxr_logger *log, struct oxr_instance *inst);
262
+
263
+
/*!
264
* @public @memberof oxr_instance
265
*/
266
XrResult
···
468
return XRT_CAST_PTR_TO_OXR_HANDLE(XrFaceTracker2FB, face_tracker2_fb);
469
}
470
#endif
471
+
472
+
#ifdef OXR_HAVE_ANDROID_face_tracking
473
+
/*!
474
+
* To go back to a OpenXR object.
475
+
*
476
+
* @relates oxr_facial_tracker_htc
477
+
*/
478
+
static inline XrFaceTrackerANDROID
479
+
oxr_face_tracker_android_to_openxr(struct oxr_face_tracker_android *face_tracker_android)
480
+
{
481
+
return XRT_CAST_PTR_TO_OXR_HANDLE(XrFaceTrackerANDROID, face_tracker_android);
482
+
}
483
+
#endif
484
+
485
/*!
486
*
487
* @name oxr_input.c
···
999
XrTime time,
1000
struct xrt_space_relation *out_relation);
1001
1002
+
/*!
1003
+
* Get the xrt_space associated with this oxr_space, the @ref xrt_space will
1004
+
* be reference counted by this function so the caller will need to call
1005
+
* @ref xrt_space_reference to decrement the reference count.
1006
+
*
1007
+
* @param log Logging struct.
1008
+
* @param spc Oxr space to get the xrt_space from.
1009
+
* @param[out] out_xspace Returns the xrt_space associated with this oxr_space.
1010
+
* @return Any errors, XR_SUCCESS, xspace is not set on XR_ERROR_*.
1011
+
*/
1012
+
XRT_CHECK_RESULT XrResult
1013
+
oxr_space_get_xrt_space(struct oxr_logger *log, struct oxr_space *spc, struct xrt_space **out_xspace);
1014
+
1015
1016
/*
1017
*
···
1122
1123
bool
1124
oxr_system_get_force_feedback_support(struct oxr_logger *log, struct oxr_instance *inst);
1125
+
1126
+
void
1127
+
oxr_system_get_face_tracking_android_support(struct oxr_logger *log, struct oxr_instance *inst, bool *supported);
1128
1129
void
1130
oxr_system_get_face_tracking_htc_support(struct oxr_logger *log,
···
1513
};
1514
1515
/*!
1516
+
* Holds the properties that a system supports for a view configuration type.
1517
+
*
1518
+
* @relates oxr_system
1519
+
*/
1520
+
struct oxr_view_config_properties
1521
+
{
1522
+
XrViewConfigurationType view_config_type;
1523
+
1524
+
uint32_t view_count;
1525
+
XrViewConfigurationView views[XRT_MAX_COMPOSITOR_VIEW_CONFIGS_VIEW_COUNT];
1526
+
1527
+
uint32_t blend_mode_count;
1528
+
XrEnvironmentBlendMode blend_modes[3];
1529
+
};
1530
+
1531
+
/*!
1532
* Single or multiple devices grouped together to form a system that sessions
1533
* can be created from. Might need to open devices to get all
1534
* properties from it, but shouldn't.
···
1560
//! Have the client application called the gfx api requirements func?
1561
bool gotten_requirements;
1562
1563
+
uint32_t view_config_count;
1564
+
struct oxr_view_config_properties view_configs[XRT_MAX_COMPOSITOR_VIEW_CONFIGS_COUNT];
1565
1566
XrReferenceSpaceType reference_spaces[5];
1567
uint32_t reference_space_count;
···
1582
//! The device returned with the last xrGetVulkanGraphicsDeviceKHR or xrGetVulkanGraphicsDevice2KHR call.
1583
//! XR_NULL_HANDLE if neither has been called.
1584
VkPhysicalDevice suggested_vulkan_physical_device;
1585
+
1586
+
/*!
1587
+
* Stores the vkGetInstanceProcAddr passed to xrCreateVulkanInstanceKHR to be
1588
+
* used when looking up Vulkan functions used by xrGetVulkanGraphicsDevice2KHR.
1589
+
*/
1590
+
PFN_vkGetInstanceProcAddr vk_get_instance_proc_addr;
1591
1592
struct
1593
{
···
1748
XrVersion major_minor;
1749
} openxr_version;
1750
1751
+
// Protects the function oxr_instance_init_system_locked.
1752
+
struct os_mutex system_init_lock;
1753
+
1754
// Hardcoded single system.
1755
struct oxr_system system;
1756
···
1810
1811
struct
1812
{
1813
+
/*!
1814
+
* Some applications can't handle depth formats, or they trigger
1815
+
* a bug in a specific version of the application or engine.
1816
+
* This flag only disables depth formats
1817
+
* @see disable_vulkan_format_depth_stencil for depth-stencil formats.
1818
+
*/
1819
+
bool disable_vulkan_format_depth;
1820
+
1821
+
/*!
1822
+
* Some applications can't handle depth stencil formats, or they
1823
+
* trigger a bug in a specific version of the application or
1824
+
* engine.
1825
+
*
1826
+
* This flag only disables depth-stencil formats,
1827
+
* @see disable_vulkan_format_depth flag for depth only formats.
1828
+
*
1829
+
* In the past it was used to work around a bug in Unreal's
1830
+
* VulkanRHI backend.
1831
+
*/
1832
bool disable_vulkan_format_depth_stencil;
1833
+
1834
//! Unreal 4 has a bug calling xrEndSession; the function should just exit
1835
bool skip_end_session;
1836
···
1892
struct oxr_session *next;
1893
1894
XrSessionState state;
1895
+
1896
+
/*!
1897
+
* This is set in xrBeginSession and is the primaryViewConfiguration
1898
+
* argument, this is then used in xrEndFrame to know which view
1899
+
* configuration the application is submitting it's frame in.
1900
+
*/
1901
+
XrViewConfigurationType current_view_config_type;
1902
1903
/*!
1904
* There is a extra state between xrBeginSession has been called and
···
3111
XrResult
3112
oxr_event_push_XrEventDataUserPresenceChangedEXT(struct oxr_logger *log, struct oxr_session *sess, bool isUserPresent);
3113
#endif // OXR_HAVE_EXT_user_presence
3114
+
3115
+
#ifdef OXR_HAVE_ANDROID_face_tracking
3116
+
/*!
3117
+
* Android specific Facial tracker.
3118
+
*
3119
+
* Parent type/handle is @ref oxr_instance
3120
+
*
3121
+
*
3122
+
* @obj{XrFaceTrackerANDROID}
3123
+
* @extends oxr_handle_base
3124
+
*/
3125
+
struct oxr_face_tracker_android
3126
+
{
3127
+
//! Common structure for things referred to by OpenXR handles.
3128
+
struct oxr_handle_base handle;
3129
+
3130
+
//! Owner of this face tracker.
3131
+
struct oxr_session *sess;
3132
+
3133
+
//! xrt_device backing this face tracker
3134
+
struct xrt_device *xdev;
3135
+
};
3136
+
3137
+
XrResult
3138
+
oxr_face_tracker_android_create(struct oxr_logger *log,
3139
+
struct oxr_session *sess,
3140
+
const XrFaceTrackerCreateInfoANDROID *createInfo,
3141
+
XrFaceTrackerANDROID *faceTracker);
3142
+
3143
+
XrResult
3144
+
oxr_get_face_state_android(struct oxr_logger *log,
3145
+
struct oxr_face_tracker_android *facial_tracker_android,
3146
+
const XrFaceStateGetInfoANDROID *getInfo,
3147
+
XrFaceStateANDROID *faceStateOutput);
3148
+
3149
+
XrResult
3150
+
oxr_get_face_calibration_state_android(struct oxr_logger *log,
3151
+
struct oxr_face_tracker_android *facial_tracker_android,
3152
+
XrBool32 *faceIsCalibratedOutput);
3153
+
#endif // OXR_HAVE_ANDROID_face_tracking
3154
3155
/*!
3156
* @}
+203
-80
src/xrt/state_trackers/oxr/oxr_session.c
+203
-80
src/xrt/state_trackers/oxr/oxr_session.c
···
1
// Copyright 2018-2024, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
65
*/
66
67
static bool
68
should_render(XrSessionState state)
69
{
70
switch (state) {
···
127
if (inst->quirks.map_stage_to_local_floor) {
128
/* When stage is mapped to local_floor:
129
* ignore stage changes
130
-
* for local_floor changes, send a duplicate envent for stage
131
* */
132
switch (ref_change->ref_type) {
133
case XRT_SPACE_REFERENCE_TYPE_STAGE: return XR_SUCCESS;
···
224
for (uint32_t i = 0; i < xc->info.format_count; i++) {
225
int64_t format = xc->info.formats[i];
226
227
-
if (inst->quirks.disable_vulkan_format_depth_stencil &&
228
-
format == 130 /* VK_FORMAT_D32_SFLOAT_S8_UINT */) {
229
continue;
230
}
231
···
249
250
struct xrt_compositor *xc = sess->compositor;
251
if (xc != NULL) {
252
-
XrViewConfigurationType view_type = beginInfo->primaryViewConfigurationType;
253
-
254
-
// in a headless session there is no compositor and primaryViewConfigurationType must be ignored
255
-
if (sess->compositor != NULL && view_type != sess->sys->view_config_type) {
256
-
/*! @todo we only support a single view config type per
257
-
* system right now */
258
-
return oxr_error(log, XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED,
259
-
"(beginInfo->primaryViewConfigurationType == "
260
-
"0x%08x) view configuration type not supported",
261
-
view_type);
262
-
}
263
-
264
const struct oxr_extension_status *extensions = &sess->sys->inst->extensions;
265
266
const struct xrt_begin_session_info begin_session_info = {
···
295
#ifdef OXR_HAVE_META_body_tracking_calibration
296
.meta_body_tracking_calibration_enabled = extensions->META_body_tracking_calibration,
297
#endif
298
};
299
300
xrt_result_t xret = xrt_comp_begin_session(xc, &begin_session_info);
···
313
// Headless, pretend we got event from the compositor.
314
sess->compositor_visible = true;
315
sess->compositor_focused = true;
316
317
// Transition into focused.
318
-
oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, 0);
319
-
oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, 0);
320
-
oxr_session_change_state(log, sess, XR_SESSION_STATE_FOCUSED, 0);
321
}
322
XrResult ret = oxr_frame_sync_begin_session(&sess->frame_sync);
323
if (ret != XR_SUCCESS) {
···
325
"Frame sync object refused to let us begin session, probably already running");
326
}
327
328
return oxr_session_success_result(sess);
329
}
330
···
372
sess->compositor_focused = false;
373
}
374
375
-
oxr_session_change_state(log, sess, XR_SESSION_STATE_IDLE, 0);
376
if (sess->exiting) {
377
-
oxr_session_change_state(log, sess, XR_SESSION_STATE_EXITING, 0);
378
} else {
379
#ifndef XRT_OS_ANDROID
380
// @todo In multi-clients scenario with a session being reused, changing session
···
391
}
392
sess->has_ended_once = false;
393
394
return oxr_session_success_result(sess);
395
}
396
397
XrResult
398
oxr_session_request_exit(struct oxr_logger *log, struct oxr_session *sess)
399
{
400
if (sess->state == XR_SESSION_STATE_FOCUSED) {
401
-
oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, 0);
402
}
403
if (sess->state == XR_SESSION_STATE_VISIBLE) {
404
-
oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, 0);
405
}
406
if (!sess->has_ended_once && sess->state != XR_SESSION_STATE_SYNCHRONIZED) {
407
-
oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, 0);
408
// Fake the synchronization.
409
sess->has_ended_once = true;
410
}
411
412
//! @todo start fading out the app.
413
-
oxr_session_change_state(log, sess, XR_SESSION_STATE_STOPPING, 0);
414
sess->exiting = true;
415
return oxr_session_success_result(sess);
416
}
···
446
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "xrt_session is null");
447
}
448
449
#ifdef XRT_OS_ANDROID
450
// Most recent Android activity lifecycle event was OnPause: move toward stopping
451
if (sess->sys->inst->activity_state == XRT_ANDROID_LIVECYCLE_EVENT_ON_PAUSE) {
452
if (sess->state == XR_SESSION_STATE_FOCUSED) {
453
U_LOG_I("Activity paused: changing session state FOCUSED->VISIBLE");
454
-
oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, 0);
455
}
456
457
if (sess->state == XR_SESSION_STATE_VISIBLE) {
458
U_LOG_I("Activity paused: changing session state VISIBLE->SYNCHRONIZED");
459
-
oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, 0);
460
}
461
462
if (sess->state == XR_SESSION_STATE_SYNCHRONIZED) {
463
U_LOG_I("Activity paused: changing session state SYNCHRONIZED->STOPPING");
464
-
oxr_session_change_state(log, sess, XR_SESSION_STATE_STOPPING, 0);
465
}
466
// TODO return here to avoid polling other events?
467
// see https://gitlab.freedesktop.org/monado/monado/-/issues/419
···
471
if (sess->sys->inst->activity_state == XRT_ANDROID_LIVECYCLE_EVENT_ON_RESUME) {
472
if (sess->state == XR_SESSION_STATE_IDLE) {
473
U_LOG_I("Activity resumed: changing session state IDLE->READY");
474
-
oxr_session_change_state(log, sess, XR_SESSION_STATE_READY, 0);
475
}
476
}
477
#endif // XRT_OS_ANDROID
···
491
case XRT_SESSION_EVENT_STATE_CHANGE:
492
sess->compositor_visible = xse.state.visible;
493
sess->compositor_focused = xse.state.focused;
494
break;
495
case XRT_SESSION_EVENT_OVERLAY_CHANGE:
496
#ifdef OXR_HAVE_EXTX_overlay
···
530
break;
531
case XRT_SESSION_EVENT_VISIBILITY_MASK_CHANGE:
532
#ifdef OXR_HAVE_KHR_visibility_mask
533
-
oxr_event_push_XrEventDataVisibilityMaskChangedKHR(log, sess, sess->sys->view_config_type,
534
-
xse.mask_change.view_index);
535
break;
536
#endif // OXR_HAVE_KHR_visibility_mask
537
case XRT_SESSION_EVENT_USER_PRESENCE_CHANGE:
···
545
}
546
547
if (sess->state == XR_SESSION_STATE_SYNCHRONIZED && sess->compositor_visible) {
548
-
oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, 0);
549
}
550
551
if (sess->state == XR_SESSION_STATE_VISIBLE && sess->compositor_focused) {
552
-
oxr_session_change_state(log, sess, XR_SESSION_STATE_FOCUSED, 0);
553
}
554
555
if (sess->state == XR_SESSION_STATE_FOCUSED && !sess->compositor_focused) {
556
-
oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, 0);
557
}
558
559
if (sess->state == XR_SESSION_STATE_VISIBLE && !sess->compositor_visible) {
560
-
oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, 0);
561
}
562
563
return XR_SUCCESS;
···
655
struct xrt_space_relation T_xdev_head = XRT_SPACE_RELATION_ZERO;
656
struct xrt_fov fovs[XRT_MAX_VIEWS] = {0};
657
struct xrt_pose poses[XRT_MAX_VIEWS] = {0};
658
659
xrt_result_t xret = xrt_device_get_view_poses( //
660
xdev, //
661
&default_eye_relation, //
662
xdisplay_time, //
663
view_count, //
664
&T_xdev_head, //
665
fovs, //
···
1047
u_hashmap_int_create(&sess->act_sets_attachments_by_key);
1048
u_hashmap_int_create(&sess->act_attachments_by_key);
1049
1050
// Done with basic init, set out variable.
1051
*out_session = sess;
1052
···
1061
} \
1062
} while (false)
1063
1064
-
#define OXR_CREATE_XRT_SESSION_AND_NATIVE_COMPOSITOR(LOG, XSI, SESS) \
1065
do { \
1066
-
if ((SESS)->sys->xsysc == NULL) { \
1067
-
return oxr_error((LOG), XR_ERROR_RUNTIME_FAILURE, \
1068
-
"The system compositor wasn't created, can't create native compositor!"); \
1069
-
} \
1070
-
xrt_result_t xret = xrt_system_create_session((SESS)->sys->xsys, (XSI), &(SESS)->xs, &(SESS)->xcn); \
1071
-
if (xret == XRT_ERROR_MULTI_SESSION_NOT_IMPLEMENTED) { \
1072
-
return oxr_error((LOG), XR_ERROR_LIMIT_REACHED, "Per instance multi-session not supported."); \
1073
-
} \
1074
-
if (xret != XRT_SUCCESS) { \
1075
-
return oxr_error((LOG), XR_ERROR_RUNTIME_FAILURE, \
1076
-
"Failed to create xrt_session and xrt_compositor_native! '%i'", xret); \
1077
-
} \
1078
-
if ((SESS)->sys->xsysc->xmcc != NULL) { \
1079
-
xrt_syscomp_set_state((SESS)->sys->xsysc, &(SESS)->xcn->base, true, true); \
1080
-
xrt_syscomp_set_z_order((SESS)->sys->xsysc, &(SESS)->xcn->base, 0); \
1081
} \
1082
} while (false)
1083
1084
-
#define OXR_SESSION_ALLOCATE_AND_INIT(LOG, SYS, GFX_TYPE, OUT) \
1085
-
do { \
1086
-
XrResult ret = oxr_session_allocate_and_init(LOG, SYS, GFX_TYPE, &OUT); \
1087
-
if (ret != XR_SUCCESS) { \
1088
-
return ret; \
1089
-
} \
1090
-
} while (0)
1091
1092
1093
/*
···
1101
const struct xrt_session_info *xsi,
1102
struct oxr_session **out_session)
1103
{
1104
#if defined(XR_USE_PLATFORM_XLIB) && defined(XR_USE_GRAPHICS_API_OPENGL)
1105
XrGraphicsBindingOpenGLXlibKHR const *opengl_xlib = OXR_GET_INPUT_FROM_CHAIN(
1106
createInfo, XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR, XrGraphicsBindingOpenGLXlibKHR);
···
1113
"xrGetOpenGL[ES]GraphicsRequirementsKHR");
1114
}
1115
1116
-
OXR_SESSION_ALLOCATE_AND_INIT(log, sys, OXR_SESSION_GRAPHICS_EXT_XLIB_GL, *out_session);
1117
-
OXR_CREATE_XRT_SESSION_AND_NATIVE_COMPOSITOR(log, xsi, *out_session);
1118
return oxr_session_populate_gl_xlib(log, sys, opengl_xlib, *out_session);
1119
}
1120
#endif
···
1132
"xrGetOpenGLESGraphicsRequirementsKHR");
1133
}
1134
1135
-
OXR_SESSION_ALLOCATE_AND_INIT(log, sys, OXR_SESSION_GRAPHICS_EXT_ANDROID_GLES, *out_session);
1136
-
OXR_CREATE_XRT_SESSION_AND_NATIVE_COMPOSITOR(log, xsi, *out_session);
1137
return oxr_session_populate_gles_android(log, sys, opengles_android, *out_session);
1138
}
1139
#endif
···
1149
"Has not called xrGetOpenGLGraphicsRequirementsKHR");
1150
}
1151
1152
-
OXR_SESSION_ALLOCATE_AND_INIT(log, sys, OXR_SESSION_GRAPHICS_EXT_WIN32_GL, *out_session);
1153
-
OXR_CREATE_XRT_SESSION_AND_NATIVE_COMPOSITOR(log, xsi, *out_session);
1154
return oxr_session_populate_gl_win32(log, sys, opengl_win32, *out_session);
1155
}
1156
#endif
···
1188
(void *)vulkan->physicalDevice, (void *)sys->suggested_vulkan_physical_device, fn);
1189
}
1190
1191
-
OXR_SESSION_ALLOCATE_AND_INIT(log, sys, OXR_SESSION_GRAPHICS_EXT_VULKAN, *out_session);
1192
-
OXR_CREATE_XRT_SESSION_AND_NATIVE_COMPOSITOR(log, xsi, *out_session);
1193
return oxr_session_populate_vk(log, sys, vulkan, *out_session);
1194
}
1195
#endif
···
1206
"xrGetOpenGL[ES]GraphicsRequirementsKHR");
1207
}
1208
1209
-
OXR_SESSION_ALLOCATE_AND_INIT(log, sys, OXR_SESSION_GRAPHICS_EXT_EGL, *out_session);
1210
-
OXR_CREATE_XRT_SESSION_AND_NATIVE_COMPOSITOR(log, xsi, *out_session);
1211
return oxr_session_populate_egl(log, sys, egl, *out_session);
1212
}
1213
#endif
···
1224
return oxr_error(log, XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING,
1225
"Has not called xrGetD3D11GraphicsRequirementsKHR");
1226
}
1227
-
XrResult result = oxr_d3d11_check_device(log, sys, d3d11->device);
1228
1229
-
if (!XR_SUCCEEDED(result)) {
1230
-
return result;
1231
}
1232
1233
1234
-
OXR_SESSION_ALLOCATE_AND_INIT(log, sys, OXR_SESSION_GRAPHICS_EXT_D3D11, *out_session);
1235
-
OXR_CREATE_XRT_SESSION_AND_NATIVE_COMPOSITOR(log, xsi, *out_session);
1236
return oxr_session_populate_d3d11(log, sys, d3d11, *out_session);
1237
}
1238
#endif
···
1249
return oxr_error(log, XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING,
1250
"Has not called xrGetD3D12GraphicsRequirementsKHR");
1251
}
1252
-
XrResult result = oxr_d3d12_check_device(log, sys, d3d12->device);
1253
1254
-
if (!XR_SUCCEEDED(result)) {
1255
-
return result;
1256
}
1257
1258
1259
-
OXR_SESSION_ALLOCATE_AND_INIT(log, sys, OXR_SESSION_GRAPHICS_EXT_D3D12, *out_session);
1260
-
OXR_CREATE_XRT_SESSION_AND_NATIVE_COMPOSITOR(log, xsi, *out_session);
1261
return oxr_session_populate_d3d12(log, sys, d3d12, *out_session);
1262
}
1263
#endif
···
1271
1272
#ifdef OXR_HAVE_MND_headless
1273
if (sys->inst->extensions.MND_headless) {
1274
-
OXR_SESSION_ALLOCATE_AND_INIT(log, sys, OXR_SESSION_GRAPHICS_EXT_HEADLESS, *out_session);
1275
(*out_session)->compositor = NULL;
1276
(*out_session)->create_swapchain = NULL;
1277
···
1320
return ret;
1321
}
1322
1323
// Everything is in order, start the state changes.
1324
-
oxr_session_change_state(log, sess, XR_SESSION_STATE_IDLE, 0);
1325
-
oxr_session_change_state(log, sess, XR_SESSION_STATE_READY, 0);
1326
1327
*out_session = sess;
1328
···
1
// Copyright 2018-2024, Collabora, Ltd.
2
+
// Copyright 2024-2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
66
*/
67
68
static bool
69
+
should_skip_format_vk_1_and_2(const struct oxr_instance *inst, uint64_t format)
70
+
{
71
+
bool skip_depth_stencil = inst->quirks.disable_vulkan_format_depth_stencil;
72
+
bool skip_stencil = false;
73
+
bool skip_depth = inst->quirks.disable_vulkan_format_depth;
74
+
75
+
// Access to Vulkan headers are not guaranteed.
76
+
switch (format) {
77
+
case 124: /* VK_FORMAT_D16_UNORM */ return skip_depth;
78
+
case 125: /* VK_FORMAT_X8_D24_UNORM_PACK32*/ return skip_depth;
79
+
case 126: /* VK_FORMAT_D32_SFLOAT */ return skip_depth;
80
+
case 127: /* VK_FORMAT_S8_UINT */ return skip_stencil;
81
+
case 129: /* VK_FORMAT_D24_UNORM_S8_UINT */ return skip_depth_stencil;
82
+
case 130: /* VK_FORMAT_D32_SFLOAT_S8_UINT */ return skip_depth_stencil;
83
+
default: return false;
84
+
}
85
+
}
86
+
87
+
static bool
88
+
should_skip_format(const struct oxr_instance *inst, const struct oxr_session *sess, uint64_t format)
89
+
{
90
+
if (sess->gfx_ext == OXR_SESSION_GRAPHICS_EXT_VULKAN) {
91
+
/*
92
+
* Hello future computer whisperer, if we split the graphics
93
+
* extension enum into Vulkan1 and Vulkan2, make sure we call this
94
+
* function for both, kthx.
95
+
*/
96
+
return should_skip_format_vk_1_and_2(inst, format);
97
+
} else {
98
+
return false;
99
+
}
100
+
}
101
+
102
+
static bool
103
should_render(XrSessionState state)
104
{
105
switch (state) {
···
162
if (inst->quirks.map_stage_to_local_floor) {
163
/* When stage is mapped to local_floor:
164
* ignore stage changes
165
+
* for local_floor changes, send a duplicate event for stage
166
* */
167
switch (ref_change->ref_type) {
168
case XRT_SPACE_REFERENCE_TYPE_STAGE: return XR_SUCCESS;
···
259
for (uint32_t i = 0; i < xc->info.format_count; i++) {
260
int64_t format = xc->info.formats[i];
261
262
+
if (should_skip_format(inst, sess, format)) {
263
continue;
264
}
265
···
283
284
struct xrt_compositor *xc = sess->compositor;
285
if (xc != NULL) {
286
const struct oxr_extension_status *extensions = &sess->sys->inst->extensions;
287
288
const struct xrt_begin_session_info begin_session_info = {
···
317
#ifdef OXR_HAVE_META_body_tracking_calibration
318
.meta_body_tracking_calibration_enabled = extensions->META_body_tracking_calibration,
319
#endif
320
+
#ifdef OXR_HAVE_ANDROID_face_tracking
321
+
.android_face_tracking_enabled = extensions->ANDROID_face_tracking,
322
+
#endif
323
};
324
325
xrt_result_t xret = xrt_comp_begin_session(xc, &begin_session_info);
···
338
// Headless, pretend we got event from the compositor.
339
sess->compositor_visible = true;
340
sess->compositor_focused = true;
341
+
342
+
int64_t now = os_monotonic_get_ns();
343
+
XrTime now_xr = time_state_monotonic_to_ts_ns(sess->sys->inst->timekeeping, now);
344
+
if (now_xr <= 0) {
345
+
// shouldn't happen but be sure to log if it does
346
+
U_LOG_W("Time keeping oddity: XR_SESSION_STATE_SYNCHRONIZED state reached at XrTime %" PRIi64,
347
+
now_xr);
348
+
}
349
350
// Transition into focused.
351
+
oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, now_xr);
352
+
oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, now_xr);
353
+
oxr_session_change_state(log, sess, XR_SESSION_STATE_FOCUSED, now_xr);
354
}
355
XrResult ret = oxr_frame_sync_begin_session(&sess->frame_sync);
356
if (ret != XR_SUCCESS) {
···
358
"Frame sync object refused to let us begin session, probably already running");
359
}
360
361
+
// Set the current view configuration type, used in xrEndFrame.
362
+
sess->current_view_config_type = beginInfo->primaryViewConfigurationType;
363
+
364
return oxr_session_success_result(sess);
365
}
366
···
408
sess->compositor_focused = false;
409
}
410
411
+
int64_t now = os_monotonic_get_ns();
412
+
XrTime now_xr = time_state_monotonic_to_ts_ns(sess->sys->inst->timekeeping, now);
413
+
if (now_xr <= 0) {
414
+
// shouldn't happen but be sure to log if it does
415
+
U_LOG_W("Time keeping oddity: ending session at XrTime %" PRIi64, now_xr);
416
+
}
417
+
418
+
oxr_session_change_state(log, sess, XR_SESSION_STATE_IDLE, now_xr);
419
if (sess->exiting) {
420
+
oxr_session_change_state(log, sess, XR_SESSION_STATE_EXITING, now_xr);
421
} else {
422
#ifndef XRT_OS_ANDROID
423
// @todo In multi-clients scenario with a session being reused, changing session
···
434
}
435
sess->has_ended_once = false;
436
437
+
// Unset the current view configuration type here.
438
+
sess->current_view_config_type = XR_VIEW_CONFIGURATION_TYPE_MAX_ENUM;
439
+
440
return oxr_session_success_result(sess);
441
}
442
443
XrResult
444
oxr_session_request_exit(struct oxr_logger *log, struct oxr_session *sess)
445
{
446
+
int64_t now = os_monotonic_get_ns();
447
+
XrTime now_xr = time_state_monotonic_to_ts_ns(sess->sys->inst->timekeeping, now);
448
+
if (now_xr <= 0) {
449
+
// shouldn't happen but be sure to log if it does
450
+
U_LOG_W("Time keeping oddity: Requesting exit at XrTime %" PRIi64, now_xr);
451
+
}
452
+
453
if (sess->state == XR_SESSION_STATE_FOCUSED) {
454
+
oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, now_xr);
455
}
456
if (sess->state == XR_SESSION_STATE_VISIBLE) {
457
+
oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, now_xr);
458
}
459
if (!sess->has_ended_once && sess->state != XR_SESSION_STATE_SYNCHRONIZED) {
460
+
oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, now_xr);
461
// Fake the synchronization.
462
sess->has_ended_once = true;
463
}
464
465
//! @todo start fading out the app.
466
+
oxr_session_change_state(log, sess, XR_SESSION_STATE_STOPPING, now_xr);
467
sess->exiting = true;
468
return oxr_session_success_result(sess);
469
}
···
499
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "xrt_session is null");
500
}
501
502
+
int64_t now = os_monotonic_get_ns();
503
+
XrTime now_xr = time_state_monotonic_to_ts_ns(sess->sys->inst->timekeeping, now);
504
+
if (now_xr <= 0) {
505
+
// shouldn't happen but be sure to log if it does
506
+
U_LOG_W("Time keeping oddity: Polling session events at XrTime %" PRIi64, now_xr);
507
+
}
508
+
509
#ifdef XRT_OS_ANDROID
510
// Most recent Android activity lifecycle event was OnPause: move toward stopping
511
if (sess->sys->inst->activity_state == XRT_ANDROID_LIVECYCLE_EVENT_ON_PAUSE) {
512
if (sess->state == XR_SESSION_STATE_FOCUSED) {
513
U_LOG_I("Activity paused: changing session state FOCUSED->VISIBLE");
514
+
oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, now_xr);
515
}
516
517
if (sess->state == XR_SESSION_STATE_VISIBLE) {
518
U_LOG_I("Activity paused: changing session state VISIBLE->SYNCHRONIZED");
519
+
oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, now_xr);
520
}
521
522
if (sess->state == XR_SESSION_STATE_SYNCHRONIZED) {
523
U_LOG_I("Activity paused: changing session state SYNCHRONIZED->STOPPING");
524
+
oxr_session_change_state(log, sess, XR_SESSION_STATE_STOPPING, now_xr);
525
}
526
// TODO return here to avoid polling other events?
527
// see https://gitlab.freedesktop.org/monado/monado/-/issues/419
···
531
if (sess->sys->inst->activity_state == XRT_ANDROID_LIVECYCLE_EVENT_ON_RESUME) {
532
if (sess->state == XR_SESSION_STATE_IDLE) {
533
U_LOG_I("Activity resumed: changing session state IDLE->READY");
534
+
oxr_session_change_state(log, sess, XR_SESSION_STATE_READY, now_xr);
535
}
536
}
537
#endif // XRT_OS_ANDROID
···
551
case XRT_SESSION_EVENT_STATE_CHANGE:
552
sess->compositor_visible = xse.state.visible;
553
sess->compositor_focused = xse.state.focused;
554
+
555
+
// Do not use xse.state.timestamp_ns, server side focused / visible state does not correspond
556
+
// 1:1 to the cycle we tell the app. In particular the compositor may have become focused /
557
+
// visible much earlier than what we tell the app when it became so.
558
+
559
break;
560
case XRT_SESSION_EVENT_OVERLAY_CHANGE:
561
#ifdef OXR_HAVE_EXTX_overlay
···
595
break;
596
case XRT_SESSION_EVENT_VISIBILITY_MASK_CHANGE:
597
#ifdef OXR_HAVE_KHR_visibility_mask
598
+
// Assume mask changed for all view configuration types.
599
+
for (uint32_t i = 0; i < sess->sys->view_config_count; i++) {
600
+
struct oxr_view_config_properties *props = &sess->sys->view_configs[i];
601
+
oxr_event_push_XrEventDataVisibilityMaskChangedKHR( //
602
+
log, //
603
+
sess, //
604
+
props->view_config_type, //
605
+
xse.mask_change.view_index); //
606
+
}
607
break;
608
#endif // OXR_HAVE_KHR_visibility_mask
609
case XRT_SESSION_EVENT_USER_PRESENCE_CHANGE:
···
617
}
618
619
if (sess->state == XR_SESSION_STATE_SYNCHRONIZED && sess->compositor_visible) {
620
+
oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, now_xr);
621
}
622
623
if (sess->state == XR_SESSION_STATE_VISIBLE && sess->compositor_focused) {
624
+
oxr_session_change_state(log, sess, XR_SESSION_STATE_FOCUSED, now_xr);
625
}
626
627
if (sess->state == XR_SESSION_STATE_FOCUSED && !sess->compositor_focused) {
628
+
oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE, now_xr);
629
}
630
631
if (sess->state == XR_SESSION_STATE_VISIBLE && !sess->compositor_visible) {
632
+
oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, now_xr);
633
}
634
635
return XR_SUCCESS;
···
727
struct xrt_space_relation T_xdev_head = XRT_SPACE_RELATION_ZERO;
728
struct xrt_fov fovs[XRT_MAX_VIEWS] = {0};
729
struct xrt_pose poses[XRT_MAX_VIEWS] = {0};
730
+
731
+
enum xrt_view_type view_type = view_count == 1 ? XRT_VIEW_TYPE_MONO : XRT_VIEW_TYPE_STEREO;
732
733
xrt_result_t xret = xrt_device_get_view_poses( //
734
xdev, //
735
&default_eye_relation, //
736
xdisplay_time, //
737
+
view_type, //
738
view_count, //
739
&T_xdev_head, //
740
fovs, //
···
1122
u_hashmap_int_create(&sess->act_sets_attachments_by_key);
1123
u_hashmap_int_create(&sess->act_attachments_by_key);
1124
1125
+
// This is set to something valid in begin session, used in xrEndFrame.
1126
+
sess->current_view_config_type = XR_VIEW_CONFIGURATION_TYPE_MAX_ENUM;
1127
+
1128
// Done with basic init, set out variable.
1129
*out_session = sess;
1130
···
1139
} \
1140
} while (false)
1141
1142
+
#define OXR_CHECK_XR_SUCCESS(LOG, FUNC, MSG) \
1143
do { \
1144
+
XrResult _xr_result = FUNC; \
1145
+
if (_xr_result != XR_SUCCESS) { \
1146
+
return oxr_error(LOG, _xr_result, MSG); \
1147
} \
1148
} while (false)
1149
1150
+
1151
+
1152
+
static XrResult
1153
+
oxr_create_xrt_session_and_native_compositor(struct oxr_logger *log,
1154
+
const struct xrt_session_info *xsi,
1155
+
struct oxr_session *sess)
1156
+
{
1157
+
if (sess->sys->xsysc == NULL) {
1158
+
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
1159
+
"The system compositor wasn't created, can't create native compositor!");
1160
+
}
1161
+
xrt_result_t xret = xrt_system_create_session(sess->sys->xsys, xsi, &sess->xs, &sess->xcn);
1162
+
if (xret == XRT_ERROR_MULTI_SESSION_NOT_IMPLEMENTED) {
1163
+
return oxr_error(log, XR_ERROR_LIMIT_REACHED, "Per instance multi-session not supported.");
1164
+
}
1165
+
if (xret != XRT_SUCCESS) {
1166
+
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
1167
+
"Failed to create xrt_session and xrt_compositor_native! '%i'", xret);
1168
+
}
1169
+
if (sess->sys->xsysc->xmcc != NULL) {
1170
+
xrt_syscomp_set_state(sess->sys->xsysc, &sess->xcn->base, true, true, os_monotonic_get_ns());
1171
+
xrt_syscomp_set_z_order(sess->sys->xsysc, &sess->xcn->base, 0);
1172
+
}
1173
+
return XR_SUCCESS;
1174
+
}
1175
+
1176
1177
1178
/*
···
1186
const struct xrt_session_info *xsi,
1187
struct oxr_session **out_session)
1188
{
1189
+
XrResult ret = XR_SUCCESS;
1190
+
1191
#if defined(XR_USE_PLATFORM_XLIB) && defined(XR_USE_GRAPHICS_API_OPENGL)
1192
XrGraphicsBindingOpenGLXlibKHR const *opengl_xlib = OXR_GET_INPUT_FROM_CHAIN(
1193
createInfo, XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR, XrGraphicsBindingOpenGLXlibKHR);
···
1200
"xrGetOpenGL[ES]GraphicsRequirementsKHR");
1201
}
1202
1203
+
ret = oxr_session_allocate_and_init(log, sys, OXR_SESSION_GRAPHICS_EXT_XLIB_GL, out_session);
1204
+
OXR_CHECK_XR_SUCCESS(log, ret, "Failed to allocate session");
1205
+
1206
+
ret = oxr_create_xrt_session_and_native_compositor(log, xsi, *out_session);
1207
+
OXR_CHECK_XR_SUCCESS(log, ret, "Failed to create session/compositor");
1208
+
1209
return oxr_session_populate_gl_xlib(log, sys, opengl_xlib, *out_session);
1210
}
1211
#endif
···
1223
"xrGetOpenGLESGraphicsRequirementsKHR");
1224
}
1225
1226
+
ret = oxr_session_allocate_and_init(log, sys, OXR_SESSION_GRAPHICS_EXT_ANDROID_GLES, out_session);
1227
+
OXR_CHECK_XR_SUCCESS(log, ret, "Failed to allocate session");
1228
+
1229
+
ret = oxr_create_xrt_session_and_native_compositor(log, xsi, *out_session);
1230
+
OXR_CHECK_XR_SUCCESS(log, ret, "Failed to create session/compositor");
1231
+
1232
return oxr_session_populate_gles_android(log, sys, opengles_android, *out_session);
1233
}
1234
#endif
···
1244
"Has not called xrGetOpenGLGraphicsRequirementsKHR");
1245
}
1246
1247
+
ret = oxr_session_allocate_and_init(log, sys, OXR_SESSION_GRAPHICS_EXT_WIN32_GL, out_session);
1248
+
OXR_CHECK_XR_SUCCESS(log, ret, "Failed to allocate session");
1249
+
1250
+
ret = oxr_create_xrt_session_and_native_compositor(log, xsi, *out_session);
1251
+
OXR_CHECK_XR_SUCCESS(log, ret, "Failed to create session/compositor");
1252
+
1253
return oxr_session_populate_gl_win32(log, sys, opengl_win32, *out_session);
1254
}
1255
#endif
···
1287
(void *)vulkan->physicalDevice, (void *)sys->suggested_vulkan_physical_device, fn);
1288
}
1289
1290
+
ret = oxr_session_allocate_and_init(log, sys, OXR_SESSION_GRAPHICS_EXT_VULKAN, out_session);
1291
+
OXR_CHECK_XR_SUCCESS(log, ret, "Failed to allocate session");
1292
+
1293
+
ret = oxr_create_xrt_session_and_native_compositor(log, xsi, *out_session);
1294
+
OXR_CHECK_XR_SUCCESS(log, ret, "Failed to create session/compositor");
1295
+
1296
return oxr_session_populate_vk(log, sys, vulkan, *out_session);
1297
}
1298
#endif
···
1309
"xrGetOpenGL[ES]GraphicsRequirementsKHR");
1310
}
1311
1312
+
ret = oxr_session_allocate_and_init(log, sys, OXR_SESSION_GRAPHICS_EXT_EGL, out_session);
1313
+
OXR_CHECK_XR_SUCCESS(log, ret, "Failed to allocate session");
1314
+
1315
+
ret = oxr_create_xrt_session_and_native_compositor(log, xsi, *out_session);
1316
+
OXR_CHECK_XR_SUCCESS(log, ret, "Failed to create session/compositor");
1317
+
1318
return oxr_session_populate_egl(log, sys, egl, *out_session);
1319
}
1320
#endif
···
1331
return oxr_error(log, XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING,
1332
"Has not called xrGetD3D11GraphicsRequirementsKHR");
1333
}
1334
+
ret = oxr_d3d11_check_device(log, sys, d3d11->device);
1335
1336
+
if (!XR_SUCCEEDED(ret)) {
1337
+
return ret;
1338
}
1339
1340
+
ret = oxr_session_allocate_and_init(log, sys, OXR_SESSION_GRAPHICS_EXT_D3D11, out_session);
1341
+
OXR_CHECK_XR_SUCCESS(log, ret, "Failed to allocate session");
1342
1343
+
ret = oxr_create_xrt_session_and_native_compositor(log, xsi, *out_session);
1344
+
OXR_CHECK_XR_SUCCESS(log, ret, "Failed to create session/compositor");
1345
+
1346
return oxr_session_populate_d3d11(log, sys, d3d11, *out_session);
1347
}
1348
#endif
···
1359
return oxr_error(log, XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING,
1360
"Has not called xrGetD3D12GraphicsRequirementsKHR");
1361
}
1362
+
ret = oxr_d3d12_check_device(log, sys, d3d12->device);
1363
1364
+
if (!XR_SUCCEEDED(ret)) {
1365
+
return ret;
1366
}
1367
1368
+
ret = oxr_session_allocate_and_init(log, sys, OXR_SESSION_GRAPHICS_EXT_D3D12, out_session);
1369
+
OXR_CHECK_XR_SUCCESS(log, ret, "Failed to allocate session");
1370
1371
+
ret = oxr_create_xrt_session_and_native_compositor(log, xsi, *out_session);
1372
+
OXR_CHECK_XR_SUCCESS(log, ret, "Failed to create session/compositor");
1373
+
1374
return oxr_session_populate_d3d12(log, sys, d3d12, *out_session);
1375
}
1376
#endif
···
1384
1385
#ifdef OXR_HAVE_MND_headless
1386
if (sys->inst->extensions.MND_headless) {
1387
+
1388
+
ret = oxr_session_allocate_and_init(log, sys, OXR_SESSION_GRAPHICS_EXT_HEADLESS, out_session);
1389
+
OXR_CHECK_XR_SUCCESS(log, ret, "Failed to allocate session");
1390
+
1391
(*out_session)->compositor = NULL;
1392
(*out_session)->create_swapchain = NULL;
1393
···
1436
return ret;
1437
}
1438
1439
+
int64_t now = os_monotonic_get_ns();
1440
+
XrTime now_xr = time_state_monotonic_to_ts_ns(sess->sys->inst->timekeeping, now);
1441
+
if (now_xr <= 0) {
1442
+
// shouldn't happen but be sure to log if it does
1443
+
U_LOG_W("Time keeping oddity: XR_SESSION_STATE_IDLE reached at XrTime %" PRIi64, now_xr);
1444
+
}
1445
+
1446
// Everything is in order, start the state changes.
1447
+
oxr_session_change_state(log, sess, XR_SESSION_STATE_IDLE, now_xr);
1448
+
oxr_session_change_state(log, sess, XR_SESSION_STATE_READY, now_xr);
1449
1450
*out_session = sess;
1451
+32
-33
src/xrt/state_trackers/oxr/oxr_session_frame_end.c
+32
-33
src/xrt/state_trackers/oxr/oxr_session_frame_end.c
···
38
#include <assert.h>
39
40
41
/*
42
*
43
* Helper functions and defines.
···
334
#endif
335
}
336
337
/*
338
*
339
* Verify functions.
···
595
return ret;
596
}
597
598
-
switch (sess->sys->view_config_type) {
599
case XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO:
600
if (proj->viewCount != 1) {
601
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
···
612
layer_index, proj->viewCount);
613
}
614
break;
615
case XR_VIEW_CONFIGURATION_TYPE_PRIMARY_QUAD_VARJO:
616
if (proj->viewCount != 4) {
617
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
···
631
default:
632
assert(false && "view type validation unimplemented");
633
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "view type %d not supported",
634
-
sess->sys->view_config_type);
635
break;
636
}
637
···
1164
#endif
1165
}
1166
1167
/*
1168
*
1169
* Submit functions.
1170
*
1171
*/
1172
1173
-
/**
1174
* Turn the poses supplied with a composition layer into the poses the compositor wants.
1175
*
1176
* @param log logger
1177
* @param sess session
1178
* @param spc space that @p pose_ptr is supplied in
1179
* @param pose_ptr pose supplied with layer
1180
-
* @param inv_offset inverse of the tracking origin offset
1181
* @param timestamp timestamp for pose
1182
* @param[out] out_pose Resulting view-space pose
1183
* @return true if successfully transformed into a view space pose
···
1187
struct oxr_session *sess,
1188
struct oxr_space *spc,
1189
const struct xrt_pose *pose_ptr,
1190
-
const struct xrt_pose *inv_offset,
1191
uint64_t timestamp,
1192
struct xrt_pose *out_pose)
1193
{
···
1241
struct oxr_logger *log,
1242
XrCompositionLayerQuad *quad,
1243
struct xrt_device *head,
1244
-
struct xrt_pose *inv_offset,
1245
uint64_t oxr_timestamp,
1246
uint64_t xrt_timestamp)
1247
{
···
1253
struct xrt_pose *pose_ptr = (struct xrt_pose *)&quad->pose;
1254
1255
struct xrt_pose pose;
1256
-
if (!handle_space(log, sess, spc, pose_ptr, inv_offset, oxr_timestamp, &pose)) {
1257
return XR_SUCCESS;
1258
}
1259
···
1292
struct oxr_logger *log,
1293
XrCompositionLayerProjection *proj,
1294
struct xrt_device *head,
1295
-
struct xrt_pose *inv_offset,
1296
uint64_t oxr_timestamp,
1297
uint64_t xrt_timestamp)
1298
{
···
1316
scs[i] = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_swapchain *, proj->views[i].subImage.swapchain);
1317
pose_ptr = (struct xrt_pose *)&proj->views[i].pose;
1318
1319
-
if (!handle_space(log, sess, spc, pose_ptr, inv_offset, oxr_timestamp, &pose[i])) {
1320
return XR_SUCCESS;
1321
}
1322
}
···
1398
struct oxr_logger *log,
1399
const XrCompositionLayerCubeKHR *cube,
1400
struct xrt_device *head,
1401
-
struct xrt_pose *inv_offset,
1402
uint64_t oxr_timestamp,
1403
uint64_t xrt_timestamp)
1404
{
···
1437
.position = XRT_VEC3_ZERO,
1438
};
1439
1440
-
if (!handle_space(log, sess, spc, &pose, inv_offset, oxr_timestamp, &data.cube.pose)) {
1441
return XR_SUCCESS;
1442
}
1443
···
1453
struct oxr_logger *log,
1454
const XrCompositionLayerCylinderKHR *cylinder,
1455
struct xrt_device *head,
1456
-
struct xrt_pose *inv_offset,
1457
uint64_t oxr_timestamp,
1458
uint64_t xrt_timestamp)
1459
{
···
1466
struct xrt_pose *pose_ptr = (struct xrt_pose *)&cylinder->pose;
1467
1468
struct xrt_pose pose;
1469
-
if (!handle_space(log, sess, spc, pose_ptr, inv_offset, oxr_timestamp, &pose)) {
1470
return XR_SUCCESS;
1471
}
1472
···
1505
struct oxr_logger *log,
1506
const XrCompositionLayerEquirectKHR *equirect,
1507
struct xrt_device *head,
1508
-
struct xrt_pose *inv_offset,
1509
uint64_t oxr_timestamp,
1510
uint64_t xrt_timestamp)
1511
{
···
1517
struct xrt_pose *pose_ptr = (struct xrt_pose *)&equirect->pose;
1518
1519
struct xrt_pose pose;
1520
-
if (!handle_space(log, sess, spc, pose_ptr, inv_offset, oxr_timestamp, &pose)) {
1521
return XR_SUCCESS;
1522
}
1523
···
1554
}
1555
1556
static void
1557
-
do_synchronize_state_change(struct oxr_logger *log, struct oxr_session *sess)
1558
{
1559
if (!sess->has_ended_once && sess->state < XR_SESSION_STATE_VISIBLE) {
1560
-
oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, 0);
1561
sess->has_ended_once = true;
1562
}
1563
}
···
1568
struct oxr_logger *log,
1569
const XrCompositionLayerEquirect2KHR *equirect,
1570
struct xrt_device *head,
1571
-
struct xrt_pose *inv_offset,
1572
uint64_t oxr_timestamp,
1573
uint64_t xrt_timestamp)
1574
{
···
1580
struct xrt_pose *pose_ptr = (struct xrt_pose *)&equirect->pose;
1581
1582
struct xrt_pose pose;
1583
-
if (!handle_space(log, sess, spc, pose_ptr, inv_offset, oxr_timestamp, &pose)) {
1584
return XR_SUCCESS;
1585
}
1586
···
1619
struct oxr_logger *log,
1620
const XrCompositionLayerPassthroughFB *passthrough,
1621
struct xrt_device *head,
1622
-
struct xrt_pose *inv_offset,
1623
uint64_t oxr_timestamp,
1624
uint64_t xrt_timestamp)
1625
{
···
1668
struct xrt_compositor *xc = sess->compositor;
1669
1670
1671
/*
1672
* Early out for headless sessions.
1673
*/
···
1678
sess->active_wait_frames--;
1679
os_mutex_unlock(&sess->active_wait_frames_lock);
1680
1681
-
do_synchronize_state_change(log, sess);
1682
1683
return oxr_session_success_result(sess);
1684
}
···
1721
sess->frame_id.begun = -1;
1722
sess->frame_started = false;
1723
1724
-
do_synchronize_state_change(log, sess);
1725
1726
return oxr_session_success_result(sess);
1727
}
···
1790
*/
1791
1792
// Do state change if needed.
1793
-
do_synchronize_state_change(log, sess);
1794
-
1795
-
struct xrt_pose inv_offset = {0};
1796
-
math_pose_invert(&xdev->tracking_origin->initial_offset, &inv_offset);
1797
1798
struct xrt_layer_frame_data data = {
1799
.frame_id = sess->frame_id.begun,
···
1811
1812
switch (layer->type) {
1813
case XR_TYPE_COMPOSITION_LAYER_PROJECTION:
1814
-
submit_projection_layer(sess, xc, log, (XrCompositionLayerProjection *)layer, xdev, &inv_offset,
1815
frameEndInfo->displayTime, xrt_display_time_ns);
1816
break;
1817
case XR_TYPE_COMPOSITION_LAYER_QUAD:
1818
-
submit_quad_layer(sess, xc, log, (XrCompositionLayerQuad *)layer, xdev, &inv_offset,
1819
frameEndInfo->displayTime, xrt_display_time_ns);
1820
break;
1821
case XR_TYPE_COMPOSITION_LAYER_CUBE_KHR:
1822
-
submit_cube_layer(sess, xc, log, (XrCompositionLayerCubeKHR *)layer, xdev, &inv_offset,
1823
frameEndInfo->displayTime, xrt_display_time_ns);
1824
break;
1825
case XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR:
1826
-
submit_cylinder_layer(sess, xc, log, (XrCompositionLayerCylinderKHR *)layer, xdev, &inv_offset,
1827
frameEndInfo->displayTime, xrt_display_time_ns);
1828
break;
1829
case XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR:
1830
-
submit_equirect1_layer(sess, xc, log, (XrCompositionLayerEquirectKHR *)layer, xdev, &inv_offset,
1831
frameEndInfo->displayTime, xrt_display_time_ns);
1832
break;
1833
case XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR:
1834
submit_equirect2_layer(sess, xc, log, (XrCompositionLayerEquirect2KHR *)layer, xdev,
1835
-
&inv_offset, frameEndInfo->displayTime, xrt_display_time_ns);
1836
break;
1837
case XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB:
1838
submit_passthrough_layer(sess, xc, log, (XrCompositionLayerPassthroughFB *)layer, xdev,
1839
-
&inv_offset, frameEndInfo->displayTime, xrt_display_time_ns);
1840
break;
1841
default: assert(false && "invalid layer type");
1842
}
···
38
#include <assert.h>
39
40
41
+
42
/*
43
*
44
* Helper functions and defines.
···
335
#endif
336
}
337
338
+
339
/*
340
*
341
* Verify functions.
···
597
return ret;
598
}
599
600
+
switch (sess->current_view_config_type) {
601
case XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO:
602
if (proj->viewCount != 1) {
603
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
···
614
layer_index, proj->viewCount);
615
}
616
break;
617
+
// This also includes XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO_WITH_FOVEATED_INSET as both values are the same
618
case XR_VIEW_CONFIGURATION_TYPE_PRIMARY_QUAD_VARJO:
619
if (proj->viewCount != 4) {
620
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
···
634
default:
635
assert(false && "view type validation unimplemented");
636
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "view type %d not supported",
637
+
sess->current_view_config_type);
638
break;
639
}
640
···
1167
#endif
1168
}
1169
1170
+
1171
/*
1172
*
1173
* Submit functions.
1174
*
1175
*/
1176
1177
+
/*!
1178
* Turn the poses supplied with a composition layer into the poses the compositor wants.
1179
*
1180
* @param log logger
1181
* @param sess session
1182
* @param spc space that @p pose_ptr is supplied in
1183
* @param pose_ptr pose supplied with layer
1184
* @param timestamp timestamp for pose
1185
* @param[out] out_pose Resulting view-space pose
1186
* @return true if successfully transformed into a view space pose
···
1190
struct oxr_session *sess,
1191
struct oxr_space *spc,
1192
const struct xrt_pose *pose_ptr,
1193
uint64_t timestamp,
1194
struct xrt_pose *out_pose)
1195
{
···
1243
struct oxr_logger *log,
1244
XrCompositionLayerQuad *quad,
1245
struct xrt_device *head,
1246
uint64_t oxr_timestamp,
1247
uint64_t xrt_timestamp)
1248
{
···
1254
struct xrt_pose *pose_ptr = (struct xrt_pose *)&quad->pose;
1255
1256
struct xrt_pose pose;
1257
+
if (!handle_space(log, sess, spc, pose_ptr, oxr_timestamp, &pose)) {
1258
return XR_SUCCESS;
1259
}
1260
···
1293
struct oxr_logger *log,
1294
XrCompositionLayerProjection *proj,
1295
struct xrt_device *head,
1296
uint64_t oxr_timestamp,
1297
uint64_t xrt_timestamp)
1298
{
···
1316
scs[i] = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_swapchain *, proj->views[i].subImage.swapchain);
1317
pose_ptr = (struct xrt_pose *)&proj->views[i].pose;
1318
1319
+
if (!handle_space(log, sess, spc, pose_ptr, oxr_timestamp, &pose[i])) {
1320
return XR_SUCCESS;
1321
}
1322
}
···
1398
struct oxr_logger *log,
1399
const XrCompositionLayerCubeKHR *cube,
1400
struct xrt_device *head,
1401
uint64_t oxr_timestamp,
1402
uint64_t xrt_timestamp)
1403
{
···
1436
.position = XRT_VEC3_ZERO,
1437
};
1438
1439
+
if (!handle_space(log, sess, spc, &pose, oxr_timestamp, &data.cube.pose)) {
1440
return XR_SUCCESS;
1441
}
1442
···
1452
struct oxr_logger *log,
1453
const XrCompositionLayerCylinderKHR *cylinder,
1454
struct xrt_device *head,
1455
uint64_t oxr_timestamp,
1456
uint64_t xrt_timestamp)
1457
{
···
1464
struct xrt_pose *pose_ptr = (struct xrt_pose *)&cylinder->pose;
1465
1466
struct xrt_pose pose;
1467
+
if (!handle_space(log, sess, spc, pose_ptr, oxr_timestamp, &pose)) {
1468
return XR_SUCCESS;
1469
}
1470
···
1503
struct oxr_logger *log,
1504
const XrCompositionLayerEquirectKHR *equirect,
1505
struct xrt_device *head,
1506
uint64_t oxr_timestamp,
1507
uint64_t xrt_timestamp)
1508
{
···
1514
struct xrt_pose *pose_ptr = (struct xrt_pose *)&equirect->pose;
1515
1516
struct xrt_pose pose;
1517
+
if (!handle_space(log, sess, spc, pose_ptr, oxr_timestamp, &pose)) {
1518
return XR_SUCCESS;
1519
}
1520
···
1551
}
1552
1553
static void
1554
+
do_synchronize_state_change(struct oxr_logger *log, struct oxr_session *sess, XrTime time)
1555
{
1556
if (!sess->has_ended_once && sess->state < XR_SESSION_STATE_VISIBLE) {
1557
+
oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED, time);
1558
sess->has_ended_once = true;
1559
}
1560
}
···
1565
struct oxr_logger *log,
1566
const XrCompositionLayerEquirect2KHR *equirect,
1567
struct xrt_device *head,
1568
uint64_t oxr_timestamp,
1569
uint64_t xrt_timestamp)
1570
{
···
1576
struct xrt_pose *pose_ptr = (struct xrt_pose *)&equirect->pose;
1577
1578
struct xrt_pose pose;
1579
+
if (!handle_space(log, sess, spc, pose_ptr, oxr_timestamp, &pose)) {
1580
return XR_SUCCESS;
1581
}
1582
···
1615
struct oxr_logger *log,
1616
const XrCompositionLayerPassthroughFB *passthrough,
1617
struct xrt_device *head,
1618
uint64_t oxr_timestamp,
1619
uint64_t xrt_timestamp)
1620
{
···
1663
struct xrt_compositor *xc = sess->compositor;
1664
1665
1666
+
int64_t now = os_monotonic_get_ns();
1667
+
XrTime now_xr = time_state_monotonic_to_ts_ns(sess->sys->inst->timekeeping, now);
1668
+
if (now_xr <= 0) {
1669
+
// shouldn't happen but be sure to log if it does
1670
+
U_LOG_W("Time keeping oddity: frame end at XrTime %" PRIi64, now_xr);
1671
+
}
1672
+
1673
/*
1674
* Early out for headless sessions.
1675
*/
···
1680
sess->active_wait_frames--;
1681
os_mutex_unlock(&sess->active_wait_frames_lock);
1682
1683
+
do_synchronize_state_change(log, sess, now_xr);
1684
1685
return oxr_session_success_result(sess);
1686
}
···
1723
sess->frame_id.begun = -1;
1724
sess->frame_started = false;
1725
1726
+
do_synchronize_state_change(log, sess, now_xr);
1727
1728
return oxr_session_success_result(sess);
1729
}
···
1792
*/
1793
1794
// Do state change if needed.
1795
+
do_synchronize_state_change(log, sess, now_xr);
1796
1797
struct xrt_layer_frame_data data = {
1798
.frame_id = sess->frame_id.begun,
···
1810
1811
switch (layer->type) {
1812
case XR_TYPE_COMPOSITION_LAYER_PROJECTION:
1813
+
submit_projection_layer(sess, xc, log, (XrCompositionLayerProjection *)layer, xdev,
1814
frameEndInfo->displayTime, xrt_display_time_ns);
1815
break;
1816
case XR_TYPE_COMPOSITION_LAYER_QUAD:
1817
+
submit_quad_layer(sess, xc, log, (XrCompositionLayerQuad *)layer, xdev,
1818
frameEndInfo->displayTime, xrt_display_time_ns);
1819
break;
1820
case XR_TYPE_COMPOSITION_LAYER_CUBE_KHR:
1821
+
submit_cube_layer(sess, xc, log, (XrCompositionLayerCubeKHR *)layer, xdev,
1822
frameEndInfo->displayTime, xrt_display_time_ns);
1823
break;
1824
case XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR:
1825
+
submit_cylinder_layer(sess, xc, log, (XrCompositionLayerCylinderKHR *)layer, xdev,
1826
frameEndInfo->displayTime, xrt_display_time_ns);
1827
break;
1828
case XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR:
1829
+
submit_equirect1_layer(sess, xc, log, (XrCompositionLayerEquirectKHR *)layer, xdev,
1830
frameEndInfo->displayTime, xrt_display_time_ns);
1831
break;
1832
case XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR:
1833
submit_equirect2_layer(sess, xc, log, (XrCompositionLayerEquirect2KHR *)layer, xdev,
1834
+
frameEndInfo->displayTime, xrt_display_time_ns);
1835
break;
1836
case XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB:
1837
submit_passthrough_layer(sess, xc, log, (XrCompositionLayerPassthroughFB *)layer, xdev,
1838
+
frameEndInfo->displayTime, xrt_display_time_ns);
1839
break;
1840
default: assert(false && "invalid layer type");
1841
}
+18
src/xrt/state_trackers/oxr/oxr_space.c
+18
src/xrt/state_trackers/oxr/oxr_space.c
···
1
// Copyright 2019-2024, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
613
614
return ret;
615
}
616
+
617
+
XrResult
618
+
oxr_space_get_xrt_space(struct oxr_logger *log, struct oxr_space *spc, struct xrt_space **out_xspace)
619
+
{
620
+
assert(out_xspace != NULL);
621
+
assert(*out_xspace == NULL);
622
+
623
+
struct xrt_space *xspace = NULL;
624
+
XrResult ret = get_xrt_space(log, spc, &xspace);
625
+
if (ret != XR_SUCCESS) {
626
+
return ret;
627
+
}
628
+
629
+
xrt_space_reference(out_xspace, xspace);
630
+
631
+
return XR_SUCCESS;
632
+
}
+224
-105
src/xrt/state_trackers/oxr/oxr_system.c
+224
-105
src/xrt/state_trackers/oxr/oxr_system.c
···
18
#include "util/u_debug.h"
19
#include "util/u_verify.h"
20
21
#include "oxr_objects.h"
22
#include "oxr_logger.h"
23
#include "oxr_two_call.h"
24
-
#include "oxr_chain.h"
25
-
#include "oxr_api_verify.h"
26
-
#include "oxr_conversions.h"
27
28
29
DEBUG_GET_ONCE_NUM_OPTION(scale_percentage, "OXR_VIEWPORT_SCALE_PERCENTAGE", 100)
30
31
32
33
static bool
34
oxr_system_matches(struct oxr_logger *log, struct oxr_system *sys, XrFormFactor form_factor)
35
{
36
return xr_form_factor_to_xrt(form_factor) == sys->xsys->properties.form_factor;
37
}
38
39
XrResult
40
oxr_system_select(struct oxr_logger *log,
41
struct oxr_system **systems,
···
98
return XR_SUCCESS;
99
}
100
101
-
102
-
103
XrResult
104
oxr_system_fill_in(
105
struct oxr_logger *log, struct oxr_instance *inst, XrSystemId systemId, uint32_t view_count, struct oxr_system *sys)
···
108
109
sys->inst = inst;
110
sys->systemId = systemId;
111
-
if (view_count == 1) {
112
-
sys->view_config_type = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO;
113
-
} else if (view_count == 2) {
114
-
sys->view_config_type = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
115
-
} else {
116
-
assert(false && "view_count must be 1 or 2");
117
-
}
118
-
U_LOG_D("sys->view_config_type = %d", sys->view_config_type);
119
sys->dynamic_roles_cache = (struct xrt_system_roles)XRT_SYSTEM_ROLES_INIT;
120
121
#ifdef XR_USE_GRAPHICS_API_VULKAN
122
sys->vulkan_enable2_instance = VK_NULL_HANDLE;
123
sys->suggested_vulkan_physical_device = VK_NULL_HANDLE;
124
#endif
125
#if defined(XR_USE_GRAPHICS_API_D3D11) || defined(XR_USE_GRAPHICS_API_D3D12)
126
U_ZERO(&(sys->suggested_d3d_luid));
127
sys->suggested_d3d_luid_valid = false;
128
#endif
129
130
-
// Headless.
131
-
if (sys->xsysc == NULL) {
132
-
sys->blend_modes[0] = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
133
-
sys->blend_mode_count = 1;
134
-
return XR_SUCCESS;
135
-
}
136
137
-
double scale = debug_get_num_option_scale_percentage() / 100.0;
138
-
if (scale > 2.0) {
139
-
scale = 2.0;
140
-
oxr_log(log, "Clamped scale to 200%%\n");
141
-
}
142
-
143
-
struct xrt_system_compositor_info *info = &sys->xsysc->info;
144
-
145
-
#define imin(a, b) (a < b ? a : b)
146
-
for (uint32_t i = 0; i < view_count; ++i) {
147
-
uint32_t w = (uint32_t)(info->views[i].recommended.width_pixels * scale);
148
-
uint32_t h = (uint32_t)(info->views[i].recommended.height_pixels * scale);
149
-
uint32_t w_2 = info->views[i].max.width_pixels;
150
-
uint32_t h_2 = info->views[i].max.height_pixels;
151
-
152
-
w = imin(w, w_2);
153
-
h = imin(h, h_2);
154
-
155
-
sys->views[i].recommendedImageRectWidth = w;
156
-
sys->views[i].maxImageRectWidth = w_2;
157
-
sys->views[i].recommendedImageRectHeight = h;
158
-
sys->views[i].maxImageRectHeight = h_2;
159
-
sys->views[i].recommendedSwapchainSampleCount = info->views[i].recommended.sample_count;
160
-
sys->views[i].maxSwapchainSampleCount = info->views[i].max.sample_count;
161
-
}
162
163
-
#undef imin
164
-
165
-
166
-
/*
167
-
* Blend mode support.
168
-
*/
169
170
-
assert(info->supported_blend_mode_count <= ARRAY_SIZE(sys->blend_modes));
171
-
assert(info->supported_blend_mode_count != 0);
172
173
-
for (uint8_t i = 0; i < info->supported_blend_mode_count; i++) {
174
-
assert(u_verify_blend_mode_valid(info->supported_blend_modes[i]));
175
-
sys->blend_modes[i] = (XrEnvironmentBlendMode)info->supported_blend_modes[i];
176
}
177
-
sys->blend_mode_count = (uint32_t)info->supported_blend_mode_count;
178
179
180
/*
···
290
OXR_CHECK_RET_IS_FFB_SUPPORTED(conforming_right)
291
#undef OXR_CHECK_RET_IS_FFB_SUPPORTED
292
return false;
293
}
294
295
void
···
351
return;
352
}
353
354
-
static bool
355
-
oxr_system_get_body_tracking_support(struct oxr_logger *log,
356
-
struct oxr_instance *inst,
357
-
const enum xrt_input_name body_tracking_name)
358
-
{
359
-
struct oxr_system *sys = &inst->system;
360
-
const struct xrt_device *body = GET_XDEV_BY_ROLE(sys, body);
361
-
if (body == NULL || !body->supported.body_tracking || body->inputs == NULL) {
362
-
return false;
363
-
}
364
-
365
-
for (size_t input_idx = 0; input_idx < body->input_count; ++input_idx) {
366
-
const struct xrt_input *input = &body->inputs[input_idx];
367
-
if (input->name == body_tracking_name) {
368
-
return true;
369
-
}
370
-
}
371
-
return false;
372
-
}
373
-
374
bool
375
oxr_system_get_body_tracking_fb_support(struct oxr_logger *log, struct oxr_instance *inst)
376
{
···
475
}
476
#endif
477
478
#ifdef OXR_HAVE_HTC_facial_tracking
479
XrSystemFacialTrackingPropertiesHTC *htc_facial_tracking_props = NULL;
480
if (sys->inst->extensions.HTC_facial_tracking) {
···
595
uint32_t *viewConfigurationTypeCountOutput,
596
XrViewConfigurationType *viewConfigurationTypes)
597
{
598
-
OXR_TWO_CALL_HELPER(log, viewConfigurationTypeCapacityInput, viewConfigurationTypeCountOutput,
599
-
viewConfigurationTypes, 1, &sys->view_config_type, XR_SUCCESS);
600
}
601
602
XrResult
···
607
uint32_t *environmentBlendModeCountOutput,
608
XrEnvironmentBlendMode *environmentBlendModes)
609
{
610
-
//! @todo Take into account viewConfigurationType
611
OXR_TWO_CALL_HELPER(log, environmentBlendModeCapacityInput, environmentBlendModeCountOutput,
612
-
environmentBlendModes, sys->blend_mode_count, sys->blend_modes, XR_SUCCESS);
613
}
614
615
XrResult
···
618
XrViewConfigurationType viewConfigurationType,
619
XrViewConfigurationProperties *configurationProperties)
620
{
621
-
if (viewConfigurationType != sys->view_config_type) {
622
-
return oxr_error(log, XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED, "Invalid view configuration type");
623
}
624
625
-
configurationProperties->viewConfigurationType = sys->view_config_type;
626
configurationProperties->fovMutable = sys->xsysc->info.supports_fov_mutable;
627
628
return XR_SUCCESS;
629
}
630
631
-
static void
632
-
view_configuration_view_fill_in(XrViewConfigurationView *target_view, XrViewConfigurationView *source_view)
633
-
{
634
-
// clang-format off
635
-
target_view->recommendedImageRectWidth = source_view->recommendedImageRectWidth;
636
-
target_view->maxImageRectWidth = source_view->maxImageRectWidth;
637
-
target_view->recommendedImageRectHeight = source_view->recommendedImageRectHeight;
638
-
target_view->maxImageRectHeight = source_view->maxImageRectHeight;
639
-
target_view->recommendedSwapchainSampleCount = source_view->recommendedSwapchainSampleCount;
640
-
target_view->maxSwapchainSampleCount = source_view->maxSwapchainSampleCount;
641
-
// clang-format on
642
-
}
643
-
644
XrResult
645
oxr_system_enumerate_view_conf_views(struct oxr_logger *log,
646
struct oxr_system *sys,
···
649
uint32_t *viewCountOutput,
650
XrViewConfigurationView *views)
651
{
652
-
if (viewConfigurationType != sys->view_config_type) {
653
-
return oxr_error(log, XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED, "Invalid view configuration type");
654
-
}
655
-
if (sys->view_config_type == XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO) {
656
-
OXR_TWO_CALL_FILL_IN_HELPER(log, viewCapacityInput, viewCountOutput, views, 1,
657
-
view_configuration_view_fill_in, sys->views, XR_SUCCESS);
658
-
} else {
659
-
OXR_TWO_CALL_FILL_IN_HELPER(log, viewCapacityInput, viewCountOutput, views, 2,
660
-
view_configuration_view_fill_in, sys->views, XR_SUCCESS);
661
}
662
}
···
18
#include "util/u_debug.h"
19
#include "util/u_verify.h"
20
21
+
#include "oxr_api_verify.h"
22
+
#include "oxr_chain.h"
23
+
#include "oxr_conversions.h"
24
#include "oxr_objects.h"
25
#include "oxr_logger.h"
26
#include "oxr_two_call.h"
27
28
29
+
/*
30
+
*
31
+
* General helpers
32
+
*
33
+
*/
34
+
35
DEBUG_GET_ONCE_NUM_OPTION(scale_percentage, "OXR_VIEWPORT_SCALE_PERCENTAGE", 100)
36
37
38
39
+
static struct oxr_view_config_properties *
40
+
get_view_config_properties(struct oxr_system *sys, XrViewConfigurationType view_config_type)
41
+
{
42
+
for (uint32_t i = 0; i < sys->view_config_count; i++) {
43
+
if (sys->view_configs[i].view_config_type == view_config_type) {
44
+
return &sys->view_configs[i];
45
+
}
46
+
}
47
+
48
+
return NULL;
49
+
}
50
+
51
+
static void
52
+
fill_in_view_config_properties_blend_modes(struct oxr_view_config_properties *props,
53
+
const struct xrt_system_compositor_info *info)
54
+
{
55
+
// Headless path.
56
+
if (info == NULL) {
57
+
props->blend_modes[0] = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
58
+
props->blend_mode_count = 1;
59
+
return;
60
+
}
61
+
62
+
assert(info->supported_blend_mode_count <= ARRAY_SIZE(props->blend_modes));
63
+
assert(info->supported_blend_mode_count != 0);
64
+
65
+
for (uint8_t i = 0; i < info->supported_blend_mode_count; i++) {
66
+
assert(u_verify_blend_mode_valid(info->supported_blend_modes[i]));
67
+
props->blend_modes[i] = (XrEnvironmentBlendMode)info->supported_blend_modes[i];
68
+
}
69
+
props->blend_mode_count = (uint32_t)info->supported_blend_mode_count;
70
+
}
71
+
72
+
static void
73
+
fill_in_view_config_properties_view_config_type(struct oxr_view_config_properties *props, enum xrt_view_type view_type)
74
+
{
75
+
props->view_config_type = xrt_view_type_to_xr(view_type);
76
+
U_LOG_D("props->view_config_type = %d", props->view_config_type);
77
+
}
78
+
79
+
static void
80
+
fill_in_view_config_properties_views(struct oxr_logger *log,
81
+
XrViewConfigurationView *xr_views,
82
+
const struct xrt_view_config *view_config)
83
+
{
84
+
assert(view_config->view_count <= XRT_MAX_COMPOSITOR_VIEW_CONFIGS_VIEW_COUNT);
85
+
86
+
double scale = debug_get_num_option_scale_percentage() / 100.0;
87
+
if (scale > 2.0) {
88
+
scale = 2.0;
89
+
oxr_log(log, "Clamped scale to 200%%\n");
90
+
}
91
+
92
+
#define imin(a, b) (a < b ? a : b)
93
+
for (uint32_t i = 0; i < view_config->view_count; ++i) {
94
+
uint32_t w = (uint32_t)(view_config->views[i].recommended.width_pixels * scale);
95
+
uint32_t h = (uint32_t)(view_config->views[i].recommended.height_pixels * scale);
96
+
uint32_t w_2 = view_config->views[i].max.width_pixels;
97
+
uint32_t h_2 = view_config->views[i].max.height_pixels;
98
+
99
+
w = imin(w, w_2);
100
+
h = imin(h, h_2);
101
+
102
+
xr_views[i].type = XR_TYPE_VIEW_CONFIGURATION_VIEW;
103
+
xr_views[i].recommendedImageRectWidth = w;
104
+
xr_views[i].maxImageRectWidth = w_2;
105
+
xr_views[i].recommendedImageRectHeight = h;
106
+
xr_views[i].maxImageRectHeight = h_2;
107
+
xr_views[i].recommendedSwapchainSampleCount = view_config->views[i].recommended.sample_count;
108
+
xr_views[i].maxSwapchainSampleCount = view_config->views[i].max.sample_count;
109
+
}
110
+
#undef imin
111
+
}
112
+
113
+
static void
114
+
fill_in_view_config_properties(struct oxr_logger *log,
115
+
struct oxr_view_config_properties *props,
116
+
const struct xrt_system_compositor_info *info,
117
+
const struct xrt_view_config *view_config)
118
+
{
119
+
fill_in_view_config_properties_blend_modes(props, info);
120
+
fill_in_view_config_properties_view_config_type(props, view_config->view_type);
121
+
fill_in_view_config_properties_views(log, props->views, view_config);
122
+
props->view_count = view_config->view_count;
123
+
}
124
+
125
static bool
126
oxr_system_matches(struct oxr_logger *log, struct oxr_system *sys, XrFormFactor form_factor)
127
{
128
return xr_form_factor_to_xrt(form_factor) == sys->xsys->properties.form_factor;
129
}
130
131
+
static bool
132
+
oxr_system_get_body_tracking_support(struct oxr_logger *log,
133
+
struct oxr_instance *inst,
134
+
const enum xrt_input_name body_tracking_name)
135
+
{
136
+
struct oxr_system *sys = &inst->system;
137
+
const struct xrt_device *body = GET_XDEV_BY_ROLE(sys, body);
138
+
if (body == NULL || !body->supported.body_tracking || body->inputs == NULL) {
139
+
return false;
140
+
}
141
+
142
+
for (size_t input_idx = 0; input_idx < body->input_count; ++input_idx) {
143
+
const struct xrt_input *input = &body->inputs[input_idx];
144
+
if (input->name == body_tracking_name) {
145
+
return true;
146
+
}
147
+
}
148
+
return false;
149
+
}
150
+
151
+
152
+
/*
153
+
*
154
+
* Two-call helpers.
155
+
*
156
+
*/
157
+
158
+
static void
159
+
view_configuration_type_fill_in(XrViewConfigurationType *target, struct oxr_view_config_properties *source)
160
+
{
161
+
*target = source->view_config_type;
162
+
}
163
+
164
+
static void
165
+
view_configuration_view_fill_in(XrViewConfigurationView *target_view, XrViewConfigurationView *source_view)
166
+
{
167
+
// clang-format off
168
+
target_view->recommendedImageRectWidth = source_view->recommendedImageRectWidth;
169
+
target_view->maxImageRectWidth = source_view->maxImageRectWidth;
170
+
target_view->recommendedImageRectHeight = source_view->recommendedImageRectHeight;
171
+
target_view->maxImageRectHeight = source_view->maxImageRectHeight;
172
+
target_view->recommendedSwapchainSampleCount = source_view->recommendedSwapchainSampleCount;
173
+
target_view->maxSwapchainSampleCount = source_view->maxSwapchainSampleCount;
174
+
// clang-format on
175
+
}
176
+
177
+
178
+
/*
179
+
*
180
+
* 'Exported' functions.
181
+
*
182
+
*/
183
+
184
XrResult
185
oxr_system_select(struct oxr_logger *log,
186
struct oxr_system **systems,
···
243
return XR_SUCCESS;
244
}
245
246
XrResult
247
oxr_system_fill_in(
248
struct oxr_logger *log, struct oxr_instance *inst, XrSystemId systemId, uint32_t view_count, struct oxr_system *sys)
···
251
252
sys->inst = inst;
253
sys->systemId = systemId;
254
sys->dynamic_roles_cache = (struct xrt_system_roles)XRT_SYSTEM_ROLES_INIT;
255
256
#ifdef XR_USE_GRAPHICS_API_VULKAN
257
sys->vulkan_enable2_instance = VK_NULL_HANDLE;
258
sys->suggested_vulkan_physical_device = VK_NULL_HANDLE;
259
+
sys->vk_get_instance_proc_addr = VK_NULL_HANDLE;
260
#endif
261
#if defined(XR_USE_GRAPHICS_API_D3D11) || defined(XR_USE_GRAPHICS_API_D3D12)
262
U_ZERO(&(sys->suggested_d3d_luid));
263
sys->suggested_d3d_luid_valid = false;
264
#endif
265
266
+
if (sys->xsysc != NULL) {
267
+
const struct xrt_system_compositor_info *info = &sys->xsysc->info;
268
269
+
for (uint32_t i = 0; i < info->view_config_count; i++) {
270
+
const struct xrt_view_config *view_config = &info->view_configs[i];
271
272
+
assert(sys->view_config_count < XRT_MAX_COMPOSITOR_VIEW_CONFIGS_COUNT);
273
+
fill_in_view_config_properties( //
274
+
log, //
275
+
&sys->view_configs[sys->view_config_count], //
276
+
info, //
277
+
view_config); //
278
+
sys->view_config_count++;
279
+
}
280
+
} else {
281
+
// Headless path, view configs contain no views but still need blend modes and view types.
282
+
assert(view_count == 1 || view_count == 2);
283
284
+
enum xrt_view_type view_type = view_count == 1 ? XRT_VIEW_TYPE_MONO : XRT_VIEW_TYPE_STEREO;
285
286
+
// First headless config: regular mono or stereo
287
+
fill_in_view_config_properties_blend_modes(&sys->view_configs[0], NULL);
288
+
fill_in_view_config_properties_view_config_type(&sys->view_configs[0], view_type);
289
+
sys->view_config_count++;
290
}
291
292
293
/*
···
403
OXR_CHECK_RET_IS_FFB_SUPPORTED(conforming_right)
404
#undef OXR_CHECK_RET_IS_FFB_SUPPORTED
405
return false;
406
+
}
407
+
408
+
void
409
+
oxr_system_get_face_tracking_android_support(struct oxr_logger *log, struct oxr_instance *inst, bool *supported)
410
+
{
411
+
assert(supported);
412
+
413
+
*supported = false;
414
+
struct oxr_system *sys = &inst->system;
415
+
const struct xrt_device *face_xdev = GET_XDEV_BY_ROLE(sys, face);
416
+
417
+
if (face_xdev == NULL || !face_xdev->supported.face_tracking || face_xdev->inputs == NULL) {
418
+
return;
419
+
}
420
+
421
+
for (size_t input_idx = 0; input_idx < face_xdev->input_count; ++input_idx) {
422
+
const struct xrt_input *input = &face_xdev->inputs[input_idx];
423
+
if (input->name == XRT_INPUT_ANDROID_FACE_TRACKING) {
424
+
*supported = true;
425
+
return;
426
+
}
427
+
}
428
}
429
430
void
···
486
return;
487
}
488
489
bool
490
oxr_system_get_body_tracking_fb_support(struct oxr_logger *log, struct oxr_instance *inst)
491
{
···
590
}
591
#endif
592
593
+
#ifdef OXR_HAVE_ANDROID_face_tracking
594
+
XrSystemFaceTrackingPropertiesANDROID *android_face_tracking_props = NULL;
595
+
if (sys->inst->extensions.ANDROID_face_tracking) {
596
+
android_face_tracking_props = OXR_GET_OUTPUT_FROM_CHAIN(
597
+
properties, XR_TYPE_SYSTEM_FACE_TRACKING_PROPERTIES_ANDROID, XrSystemFaceTrackingPropertiesANDROID);
598
+
}
599
+
600
+
if (android_face_tracking_props) {
601
+
bool supported = false;
602
+
oxr_system_get_face_tracking_android_support(log, sys->inst, &supported);
603
+
android_face_tracking_props->supportsFaceTracking = supported;
604
+
}
605
+
#endif // OXR_HAVE_HTC_facial_tracking
606
+
607
#ifdef OXR_HAVE_HTC_facial_tracking
608
XrSystemFacialTrackingPropertiesHTC *htc_facial_tracking_props = NULL;
609
if (sys->inst->extensions.HTC_facial_tracking) {
···
724
uint32_t *viewConfigurationTypeCountOutput,
725
XrViewConfigurationType *viewConfigurationTypes)
726
{
727
+
OXR_TWO_CALL_FILL_IN_HELPER(log, viewConfigurationTypeCapacityInput, viewConfigurationTypeCountOutput,
728
+
viewConfigurationTypes, sys->view_config_count, view_configuration_type_fill_in,
729
+
sys->view_configs, XR_SUCCESS);
730
}
731
732
XrResult
···
737
uint32_t *environmentBlendModeCountOutput,
738
XrEnvironmentBlendMode *environmentBlendModes)
739
{
740
+
struct oxr_view_config_properties *props = get_view_config_properties(sys, viewConfigurationType);
741
+
if (props == NULL) {
742
+
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Didn't find view configs");
743
+
}
744
+
745
OXR_TWO_CALL_HELPER(log, environmentBlendModeCapacityInput, environmentBlendModeCountOutput,
746
+
environmentBlendModes, props->blend_mode_count, props->blend_modes, XR_SUCCESS);
747
}
748
749
XrResult
···
752
XrViewConfigurationType viewConfigurationType,
753
XrViewConfigurationProperties *configurationProperties)
754
{
755
+
struct oxr_view_config_properties *props = get_view_config_properties(sys, viewConfigurationType);
756
+
if (props == NULL) {
757
+
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Didn't find view configs");
758
}
759
760
+
configurationProperties->viewConfigurationType = props->view_config_type;
761
configurationProperties->fovMutable = sys->xsysc->info.supports_fov_mutable;
762
763
return XR_SUCCESS;
764
}
765
766
XrResult
767
oxr_system_enumerate_view_conf_views(struct oxr_logger *log,
768
struct oxr_system *sys,
···
771
uint32_t *viewCountOutput,
772
XrViewConfigurationView *views)
773
{
774
+
struct oxr_view_config_properties *props = get_view_config_properties(sys, viewConfigurationType);
775
+
if (props == NULL) {
776
+
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Didn't find view configs");
777
}
778
+
779
+
OXR_TWO_CALL_FILL_IN_HELPER(log, viewCapacityInput, viewCountOutput, views, props->view_count,
780
+
view_configuration_view_fill_in, props->views, XR_SUCCESS);
781
}
+36
-12
src/xrt/state_trackers/oxr/oxr_two_call.h
+36
-12
src/xrt/state_trackers/oxr/oxr_two_call.h
···
14
extern "C" {
15
#endif
16
17
-
18
-
#define OXR_TWO_CALL_HELPER(log, cnt_input, cnt_output, output, count, data, sval) \
19
do { \
20
if ((cnt_output) == NULL) { \
21
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, #cnt_output); \
···
28
if ((cnt_input) < (uint32_t)(count)) { \
29
return oxr_error(log, XR_ERROR_SIZE_INSUFFICIENT, #cnt_input); \
30
} \
31
for (uint32_t i = 0; i < (count); i++) { \
32
(output)[i] = (data)[i]; \
33
} \
···
37
//! Calls fill_fn(&output_struct[i], &source_struct[i]) to fill output_structs
38
#define OXR_TWO_CALL_FILL_IN_HELPER(log, cnt_input, cnt_output, output_structs, count, fill_fn, source_structs, sval) \
39
do { \
40
-
if (cnt_output == NULL) { \
41
-
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, #cnt_output); \
42
-
} \
43
-
*cnt_output = count; \
44
\
45
-
if (cnt_input == 0) { \
46
-
return sval; \
47
-
} \
48
-
if (cnt_input < count) { \
49
-
return oxr_error(log, XR_ERROR_SIZE_INSUFFICIENT, #cnt_input); \
50
-
} \
51
for (uint32_t i = 0; i < count; i++) { \
52
fill_fn(&output_structs[i], &source_structs[i]); \
53
} \
54
return sval; \
55
} while (false)
56
57
#ifdef __cplusplus
···
14
extern "C" {
15
#endif
16
17
+
#define OXR_TWO_CALL_CHECK_ONLY(log, cnt_input, cnt_output, count, sval) \
18
do { \
19
if ((cnt_output) == NULL) { \
20
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, #cnt_output); \
···
27
if ((cnt_input) < (uint32_t)(count)) { \
28
return oxr_error(log, XR_ERROR_SIZE_INSUFFICIENT, #cnt_input); \
29
} \
30
+
} while (false)
31
+
32
+
#define OXR_TWO_CALL_CHECK_GOTO(log, cnt_input, cnt_output, count, sval, goto_label) \
33
+
do { \
34
+
if ((cnt_output) == NULL) { \
35
+
sval = oxr_error(log, XR_ERROR_VALIDATION_FAILURE, #cnt_output); \
36
+
goto goto_label; \
37
+
} \
38
+
*(cnt_output) = (uint32_t)(count); \
39
+
\
40
+
if ((cnt_input) == 0) { \
41
+
goto goto_label; \
42
+
} \
43
+
if ((cnt_input) < (uint32_t)(count)) { \
44
+
sval = oxr_error(log, XR_ERROR_SIZE_INSUFFICIENT, #cnt_input); \
45
+
goto goto_label; \
46
+
} \
47
+
} while (false)
48
+
49
+
#define OXR_TWO_CALL_HELPER(log, cnt_input, cnt_output, output, count, data, sval) \
50
+
do { \
51
+
OXR_TWO_CALL_CHECK_ONLY(log, cnt_input, cnt_output, count, sval); \
52
+
\
53
for (uint32_t i = 0; i < (count); i++) { \
54
(output)[i] = (data)[i]; \
55
} \
···
59
//! Calls fill_fn(&output_struct[i], &source_struct[i]) to fill output_structs
60
#define OXR_TWO_CALL_FILL_IN_HELPER(log, cnt_input, cnt_output, output_structs, count, fill_fn, source_structs, sval) \
61
do { \
62
+
OXR_TWO_CALL_CHECK_ONLY(log, cnt_input, cnt_output, count, sval); \
63
\
64
for (uint32_t i = 0; i < count; i++) { \
65
fill_fn(&output_structs[i], &source_structs[i]); \
66
} \
67
return sval; \
68
+
} while (false)
69
+
70
+
//! Calls fill_fn(&output_struct[i], &source_struct[i]) to fill output_structs
71
+
#define OXR_TWO_CALL_FILL_IN_GOTO(log, cnt_input, cnt_output, output_structs, count, fill_macro, source_structs, sval, \
72
+
goto_label) \
73
+
do { \
74
+
OXR_TWO_CALL_CHECK_GOTO(log, cnt_input, cnt_output, count, sval, goto_label); \
75
+
\
76
+
for (uint32_t i = 0; i < count; i++) { \
77
+
fill_macro(output_structs[i], source_structs[i]); \
78
+
} \
79
} while (false)
80
81
#ifdef __cplusplus
+22
src/xrt/state_trackers/oxr/oxr_verify.c
+22
src/xrt/state_trackers/oxr/oxr_verify.c
···
1
// Copyright 2018-2022, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
424
}
425
#endif
426
427
if (extensions->EXT_dpad_binding && !extensions->KHR_binding_modification) {
428
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
429
"XR_EXT_dpad_binding requires XR_KHR_binding_modification");
430
}
431
432
return XR_SUCCESS;
433
}
···
444
return XR_SUCCESS;
445
}
446
447
if (OXR_API_VERSION_AT_LEAST(inst, 1, 1)) {
448
if (view_conf == XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO_WITH_FOVEATED_INSET) {
449
return XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED;
···
452
453
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, "(%s == 0x%08x) invalid view configuration type",
454
view_conf_name, view_conf);
455
}
456
457
XrResult
···
1
// Copyright 2018-2022, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
425
}
426
#endif
427
428
+
#ifdef OXR_HAVE_EXT_dpad_binding
429
if (extensions->EXT_dpad_binding && !extensions->KHR_binding_modification) {
430
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
431
"XR_EXT_dpad_binding requires XR_KHR_binding_modification");
432
}
433
+
#endif
434
435
return XR_SUCCESS;
436
}
···
447
return XR_SUCCESS;
448
}
449
450
+
// Valid in OpenXR 1.1 and forward.
451
if (OXR_API_VERSION_AT_LEAST(inst, 1, 1)) {
452
if (view_conf == XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO_WITH_FOVEATED_INSET) {
453
return XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED;
···
456
457
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, "(%s == 0x%08x) invalid view configuration type",
458
view_conf_name, view_conf);
459
+
}
460
+
461
+
XrResult
462
+
oxr_verify_view_config_type_supported(struct oxr_logger *log,
463
+
struct oxr_system *sys,
464
+
XrViewConfigurationType view_conf,
465
+
const char *view_conf_name)
466
+
{
467
+
for (uint32_t i = 0; i < sys->view_config_count; i++) {
468
+
struct oxr_view_config_properties *props = &sys->view_configs[i];
469
+
if (props->view_config_type == view_conf) {
470
+
return XR_SUCCESS;
471
+
}
472
+
}
473
+
474
+
return oxr_error(log, XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED,
475
+
"(%s == 0x%08x) unsupported view configuration type by system %zu", view_conf_name, view_conf,
476
+
sys->systemId);
477
}
478
479
XrResult
+41
-45
src/xrt/state_trackers/oxr/oxr_vulkan.c
+41
-45
src/xrt/state_trackers/oxr/oxr_vulkan.c
···
1
// Copyright 2018-2024, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
31
*
32
*/
33
34
-
#define GET_PROC(name) PFN_##name name = (PFN_##name)getProc(vkInstance, #name)
35
36
#define UUID_STR_SIZE (XRT_UUID_SIZE * 3 + 1)
37
···
190
191
static XrResult
192
vk_get_instance_ext_props(struct oxr_logger *log,
193
-
VkInstance instance,
194
-
PFN_vkGetInstanceProcAddr GetInstanceProcAddr,
195
VkExtensionProperties **out_props,
196
uint32_t *out_prop_count)
197
{
198
-
PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties =
199
-
(PFN_vkEnumerateInstanceExtensionProperties)vkGetInstanceProcAddr(NULL,
200
-
"vkEnumerateInstanceExtensionProperties");
201
202
-
if (!EnumerateInstanceExtensionProperties) {
203
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
204
-
"Failed to get EnumerateInstanceExtensionProperties fp");
205
}
206
207
uint32_t prop_count = 0;
208
-
VkResult res = EnumerateInstanceExtensionProperties(NULL, &prop_count, NULL);
209
if (res != VK_SUCCESS) {
210
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
211
"Failed to enumerate instance extension properties count (%d)", res);
···
214
215
VkExtensionProperties *props = U_TYPED_ARRAY_CALLOC(VkExtensionProperties, prop_count);
216
217
-
res = EnumerateInstanceExtensionProperties(NULL, &prop_count, props);
218
if (res != VK_SUCCESS) {
219
free(props);
220
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
···
235
VkResult *vulkanResult)
236
{
237
238
-
PFN_vkGetInstanceProcAddr GetInstanceProcAddr = createInfo->pfnGetInstanceProcAddr;
239
240
-
PFN_vkCreateInstance CreateInstance = (PFN_vkCreateInstance)GetInstanceProcAddr(NULL, "vkCreateInstance");
241
-
if (!CreateInstance) {
242
//! @todo: clarify in spec
243
*vulkanResult = VK_ERROR_INITIALIZATION_FAILED;
244
return XR_SUCCESS;
···
284
modified_info.ppEnabledExtensionNames = u_string_list_get_data(instance_ext_list);
285
modified_info.enabledExtensionCount = u_string_list_get_size(instance_ext_list);
286
287
-
*vulkanResult = CreateInstance(&modified_info, createInfo->vulkanAllocator, vulkanInstance);
288
289
290
// Logging
···
315
316
static XrResult
317
vk_get_device_ext_props(struct oxr_logger *log,
318
-
VkInstance instance,
319
-
PFN_vkGetInstanceProcAddr GetInstanceProcAddr,
320
VkPhysicalDevice physical_device,
321
VkExtensionProperties **out_props,
322
uint32_t *out_prop_count)
323
{
324
-
PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties =
325
-
(PFN_vkEnumerateDeviceExtensionProperties)GetInstanceProcAddr(instance,
326
-
"vkEnumerateDeviceExtensionProperties");
327
328
-
if (!EnumerateDeviceExtensionProperties) {
329
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
330
-
"Failed to get vkEnumerateDeviceExtensionProperties fp");
331
}
332
333
uint32_t prop_count = 0;
334
-
VkResult res = EnumerateDeviceExtensionProperties(physical_device, NULL, &prop_count, NULL);
335
if (res != VK_SUCCESS) {
336
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
337
"Failed to enumerate device extension properties count (%d)", res);
···
340
341
VkExtensionProperties *props = U_TYPED_ARRAY_CALLOC(VkExtensionProperties, prop_count);
342
343
-
res = EnumerateDeviceExtensionProperties(physical_device, NULL, &prop_count, props);
344
if (res != VK_SUCCESS) {
345
free(props);
346
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to enumerate device extension properties (%d)",
···
355
356
static XrResult
357
vk_get_device_features(struct oxr_logger *log,
358
-
VkInstance instance,
359
-
PFN_vkGetInstanceProcAddr GetInstanceProcAddr,
360
VkPhysicalDevice physical_device,
361
VkPhysicalDeviceFeatures2KHR *physical_device_features)
362
{
363
-
PFN_vkGetPhysicalDeviceFeatures2KHR GetPhysicalDeviceFeatures2 =
364
-
(PFN_vkGetPhysicalDeviceFeatures2KHR)GetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2KHR");
365
366
-
if (!GetPhysicalDeviceFeatures2) {
367
-
oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to get vkGetPhysicalDeviceFeatures2 fp");
368
}
369
370
-
GetPhysicalDeviceFeatures2( //
371
-
physical_device, // physicalDevice
372
-
physical_device_features); // pFeatures
373
374
return XR_SUCCESS;
375
}
···
395
{
396
XrResult res;
397
398
-
PFN_vkGetInstanceProcAddr GetInstanceProcAddr = createInfo->pfnGetInstanceProcAddr;
399
400
-
PFN_vkCreateDevice CreateDevice =
401
-
(PFN_vkCreateDevice)GetInstanceProcAddr(sys->vulkan_enable2_instance, "vkCreateDevice");
402
-
if (!CreateDevice) {
403
//! @todo: clarify in spec
404
*vulkanResult = VK_ERROR_INITIALIZATION_FAILED;
405
return XR_SUCCESS;
···
513
}
514
#endif
515
516
-
*vulkanResult = CreateDevice(physical_device, &modified_info, createInfo->vulkanAllocator, vulkanDevice);
517
518
519
// Logging
···
571
oxr_vk_get_physical_device(struct oxr_logger *log,
572
struct oxr_instance *inst,
573
struct oxr_system *sys,
574
-
VkInstance vkInstance,
575
-
PFN_vkGetInstanceProcAddr getProc,
576
VkPhysicalDevice *vkPhysicalDevice)
577
{
578
-
GET_PROC(vkEnumeratePhysicalDevices);
579
-
GET_PROC(vkGetPhysicalDeviceProperties2KHR);
580
VkResult vk_ret;
581
uint32_t count;
582
···
584
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, " sys->xsysc == NULL");
585
}
586
587
-
vk_ret = vkEnumeratePhysicalDevices(vkInstance, &count, NULL);
588
if (vk_ret != VK_SUCCESS) {
589
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Call to vkEnumeratePhysicalDevices returned %u",
590
vk_ret);
···
595
}
596
597
VkPhysicalDevice *phys = U_TYPED_ARRAY_CALLOC(VkPhysicalDevice, count);
598
-
vk_ret = vkEnumeratePhysicalDevices(vkInstance, &count, phys);
599
if (vk_ret != VK_SUCCESS) {
600
free(phys);
601
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Call to vkEnumeratePhysicalDevices returned %u",
···
622
.pNext = &pdidp,
623
};
624
625
-
vkGetPhysicalDeviceProperties2KHR(phys[i], &pdp2);
626
627
// These should always be true
628
static_assert(VK_UUID_SIZE == XRT_UUID_SIZE, "uuid sizes mismatch");
···
656
657
// vulkan_enable2 needs the physical device in xrCreateVulkanDeviceKHR
658
if (inst->extensions.KHR_vulkan_enable2) {
659
-
sys->vulkan_enable2_instance = vkInstance;
660
}
661
sys->suggested_vulkan_physical_device = *vkPhysicalDevice;
662
if (log_level <= U_LOGGING_DEBUG) {
···
1
// Copyright 2018-2024, Collabora, Ltd.
2
+
// Copyright 2024-2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
32
*
33
*/
34
35
+
#define GET_PROC(INST, NAME) PFN_vk##NAME loaded_##NAME = (PFN_vk##NAME)vulkanGetInstanceProcAddr(INST, "vk" #NAME)
36
37
#define UUID_STR_SIZE (XRT_UUID_SIZE * 3 + 1)
38
···
191
192
static XrResult
193
vk_get_instance_ext_props(struct oxr_logger *log,
194
+
VkInstance vulkanInstance,
195
+
PFN_vkGetInstanceProcAddr vulkanGetInstanceProcAddr,
196
VkExtensionProperties **out_props,
197
uint32_t *out_prop_count)
198
{
199
+
GET_PROC(vulkanInstance, EnumerateInstanceExtensionProperties);
200
201
+
if (!loaded_EnumerateInstanceExtensionProperties) {
202
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
203
+
"Failed to get vkEnumerateInstanceExtensionProperties function pointer.");
204
}
205
206
uint32_t prop_count = 0;
207
+
VkResult res = loaded_EnumerateInstanceExtensionProperties(NULL, &prop_count, NULL);
208
if (res != VK_SUCCESS) {
209
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
210
"Failed to enumerate instance extension properties count (%d)", res);
···
213
214
VkExtensionProperties *props = U_TYPED_ARRAY_CALLOC(VkExtensionProperties, prop_count);
215
216
+
res = loaded_EnumerateInstanceExtensionProperties(NULL, &prop_count, props);
217
if (res != VK_SUCCESS) {
218
free(props);
219
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
···
234
VkResult *vulkanResult)
235
{
236
237
+
PFN_vkGetInstanceProcAddr vulkanGetInstanceProcAddr = createInfo->pfnGetInstanceProcAddr;
238
+
GET_PROC(NULL, CreateInstance);
239
240
+
if (!loaded_CreateInstance) {
241
//! @todo: clarify in spec
242
*vulkanResult = VK_ERROR_INITIALIZATION_FAILED;
243
return XR_SUCCESS;
···
283
modified_info.ppEnabledExtensionNames = u_string_list_get_data(instance_ext_list);
284
modified_info.enabledExtensionCount = u_string_list_get_size(instance_ext_list);
285
286
+
*vulkanResult = loaded_CreateInstance(&modified_info, createInfo->vulkanAllocator, vulkanInstance);
287
288
289
// Logging
···
314
315
static XrResult
316
vk_get_device_ext_props(struct oxr_logger *log,
317
+
VkInstance vulkanInstance,
318
+
PFN_vkGetInstanceProcAddr vulkanGetInstanceProcAddr,
319
VkPhysicalDevice physical_device,
320
VkExtensionProperties **out_props,
321
uint32_t *out_prop_count)
322
{
323
+
GET_PROC(vulkanInstance, EnumerateDeviceExtensionProperties);
324
325
+
if (!loaded_EnumerateDeviceExtensionProperties) {
326
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
327
+
"Failed to get vkEnumerateDeviceExtensionProperties function pointer");
328
}
329
330
uint32_t prop_count = 0;
331
+
VkResult res = loaded_EnumerateDeviceExtensionProperties(physical_device, NULL, &prop_count, NULL);
332
if (res != VK_SUCCESS) {
333
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
334
"Failed to enumerate device extension properties count (%d)", res);
···
337
338
VkExtensionProperties *props = U_TYPED_ARRAY_CALLOC(VkExtensionProperties, prop_count);
339
340
+
res = loaded_EnumerateDeviceExtensionProperties(physical_device, NULL, &prop_count, props);
341
if (res != VK_SUCCESS) {
342
free(props);
343
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to enumerate device extension properties (%d)",
···
352
353
static XrResult
354
vk_get_device_features(struct oxr_logger *log,
355
+
VkInstance vulkanInstance,
356
+
PFN_vkGetInstanceProcAddr vulkanGetInstanceProcAddr,
357
VkPhysicalDevice physical_device,
358
VkPhysicalDeviceFeatures2KHR *physical_device_features)
359
{
360
+
GET_PROC(vulkanInstance, GetPhysicalDeviceFeatures2KHR);
361
362
+
if (!loaded_GetPhysicalDeviceFeatures2KHR) {
363
+
oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to get vkGetPhysicalDeviceFeatures2KHR fp");
364
}
365
366
+
loaded_GetPhysicalDeviceFeatures2KHR( //
367
+
physical_device, // physicalDevice
368
+
physical_device_features); // pFeatures
369
370
return XR_SUCCESS;
371
}
···
391
{
392
XrResult res;
393
394
+
PFN_vkGetInstanceProcAddr vulkanGetInstanceProcAddr = createInfo->pfnGetInstanceProcAddr;
395
+
GET_PROC(sys->vulkan_enable2_instance, CreateDevice);
396
397
+
if (!loaded_CreateDevice) {
398
//! @todo: clarify in spec
399
*vulkanResult = VK_ERROR_INITIALIZATION_FAILED;
400
return XR_SUCCESS;
···
508
}
509
#endif
510
511
+
*vulkanResult = loaded_CreateDevice(physical_device, &modified_info, createInfo->vulkanAllocator, vulkanDevice);
512
513
514
// Logging
···
566
oxr_vk_get_physical_device(struct oxr_logger *log,
567
struct oxr_instance *inst,
568
struct oxr_system *sys,
569
+
VkInstance vulkanInstance,
570
+
PFN_vkGetInstanceProcAddr vulkanGetInstanceProcAddr,
571
VkPhysicalDevice *vkPhysicalDevice)
572
{
573
+
GET_PROC(vulkanInstance, EnumeratePhysicalDevices);
574
+
GET_PROC(vulkanInstance, GetPhysicalDeviceProperties2KHR);
575
+
576
VkResult vk_ret;
577
uint32_t count;
578
···
580
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, " sys->xsysc == NULL");
581
}
582
583
+
vk_ret = loaded_EnumeratePhysicalDevices(vulkanInstance, &count, NULL);
584
if (vk_ret != VK_SUCCESS) {
585
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Call to vkEnumeratePhysicalDevices returned %u",
586
vk_ret);
···
591
}
592
593
VkPhysicalDevice *phys = U_TYPED_ARRAY_CALLOC(VkPhysicalDevice, count);
594
+
vk_ret = loaded_EnumeratePhysicalDevices(vulkanInstance, &count, phys);
595
if (vk_ret != VK_SUCCESS) {
596
free(phys);
597
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Call to vkEnumeratePhysicalDevices returned %u",
···
618
.pNext = &pdidp,
619
};
620
621
+
loaded_GetPhysicalDeviceProperties2KHR(phys[i], &pdp2);
622
623
// These should always be true
624
static_assert(VK_UUID_SIZE == XRT_UUID_SIZE, "uuid sizes mismatch");
···
652
653
// vulkan_enable2 needs the physical device in xrCreateVulkanDeviceKHR
654
if (inst->extensions.KHR_vulkan_enable2) {
655
+
sys->vulkan_enable2_instance = vulkanInstance;
656
}
657
sys->suggested_vulkan_physical_device = *vkPhysicalDevice;
658
if (log_level <= U_LOGGING_DEBUG) {
+22
-2
src/xrt/state_trackers/oxr/oxr_xret.h
+22
-2
src/xrt/state_trackers/oxr/oxr_xret.h
···
24
xrt_result_t check_ret = (RESULTS); \
25
if (check_ret == XRT_ERROR_IPC_FAILURE) { \
26
(SESS)->has_lost = true; \
27
-
return oxr_error(LOG, XR_ERROR_INSTANCE_LOST, "Call to " #FUNCTION " failed"); \
28
} \
29
if (check_ret != XRT_SUCCESS) { \
30
-
return oxr_error(LOG, XR_ERROR_RUNTIME_FAILURE, "Call to " #FUNCTION " failed"); \
31
} \
32
} while (false)
···
24
xrt_result_t check_ret = (RESULTS); \
25
if (check_ret == XRT_ERROR_IPC_FAILURE) { \
26
(SESS)->has_lost = true; \
27
+
return oxr_error((LOG), XR_ERROR_INSTANCE_LOST, "Call to " #FUNCTION " failed"); \
28
} \
29
if (check_ret != XRT_SUCCESS) { \
30
+
return oxr_error((LOG), XR_ERROR_RUNTIME_FAILURE, "Call to " #FUNCTION " failed"); \
31
+
} \
32
+
} while (false)
33
+
34
+
#define OXR_CHECK_XRET_ALWAYS_RET(LOG, SESS, RESULTS, FUNCTION) \
35
+
do { \
36
+
OXR_CHECK_XRET(LOG, SESS, RESULTS, FUNCTION); \
37
+
return XR_SUCCESS; \
38
+
} while (false)
39
+
40
+
#define OXR_CHECK_XRET_GOTO(LOG, SESS, RESULTS, FUNCTION, XR_RES, GOTO_LABEL) \
41
+
do { \
42
+
xrt_result_t check_ret = (RESULTS); \
43
+
if (check_ret == XRT_ERROR_IPC_FAILURE) { \
44
+
(SESS)->has_lost = true; \
45
+
XR_RES = oxr_error(LOG, XR_ERROR_INSTANCE_LOST, "Call to " #FUNCTION " failed"); \
46
+
goto GOTO_LABEL; \
47
+
} \
48
+
if (check_ret != XRT_SUCCESS) { \
49
+
XR_RES = oxr_error(LOG, XR_ERROR_RUNTIME_FAILURE, "Call to " #FUNCTION " failed"); \
50
+
goto GOTO_LABEL; \
51
} \
52
} while (false)
+2
-1
src/xrt/state_trackers/steamvr_drv/ovrd_driver.cpp
+2
-1
src/xrt/state_trackers/steamvr_drv/ovrd_driver.cpp
···
1108
1109
//! @todo more than 2 views
1110
struct xrt_space_relation head_relation;
1111
-
xrt_device_get_view_poses(xdev, &ipd_vec, now_ns, 2, &head_relation, m_fovs, m_view_pose);
1112
1113
//! @todo more versatile IPD calculation
1114
float actual_ipd = -m_view_pose[0].position.x + m_view_pose[1].position.x;
···
1108
1109
//! @todo more than 2 views
1110
struct xrt_space_relation head_relation;
1111
+
xrt_device_get_view_poses(xdev, &ipd_vec, now_ns, XRT_VIEW_TYPE_STEREO, 2, &head_relation, m_fovs,
1112
+
m_view_pose);
1113
1114
//! @todo more versatile IPD calculation
1115
float actual_ipd = -m_view_pose[0].position.x + m_view_pose[1].position.x;
+14
src/xrt/targets/common/target_instance.c
+14
src/xrt/targets/common/target_instance.c
···
1
// Copyright 2020-2024, Collabora, Ltd.
2
// SPDX-License-Identifier: BSL-1.0
3
/*!
4
* @file
···
50
* Internal functions.
51
*
52
*/
53
54
static xrt_result_t
55
t_instance_create_system(struct xrt_instance *xinst,
···
168
}
169
170
struct t_instance *tinst = U_TYPED_CALLOC(struct t_instance);
171
tinst->base.create_system = t_instance_create_system;
172
tinst->base.get_prober = t_instance_get_prober;
173
tinst->base.destroy = t_instance_destroy;
···
1
// Copyright 2020-2024, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
51
* Internal functions.
52
*
53
*/
54
+
55
+
static xrt_result_t
56
+
t_instance_is_system_available(struct xrt_instance *xinst, bool *out_available)
57
+
{
58
+
XRT_TRACE_MARKER();
59
+
60
+
assert(out_available != NULL);
61
+
62
+
*out_available = true;
63
+
64
+
return XRT_SUCCESS;
65
+
}
66
67
static xrt_result_t
68
t_instance_create_system(struct xrt_instance *xinst,
···
181
}
182
183
struct t_instance *tinst = U_TYPED_CALLOC(struct t_instance);
184
+
tinst->base.is_system_available = t_instance_is_system_available;
185
tinst->base.create_system = t_instance_create_system;
186
tinst->base.get_prober = t_instance_get_prober;
187
tinst->base.destroy = t_instance_destroy;
+11
src/xrt/targets/ctl/main.c
+11
src/xrt/targets/ctl/main.c
···
1
// Copyright 2020-2024, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
315
if (xret != XRT_SUCCESS) {
316
U_LOG_E("ipc_client_connection_init: %u", xret);
317
return -1;
318
+
}
319
+
320
+
bool is_system_available = false;
321
+
xret = ipc_call_instance_is_system_available(&ipc_c, &is_system_available);
322
+
if (xret != XRT_SUCCESS) {
323
+
U_LOG_E("ipc_call_instance_is_system_available: %u", xret);
324
+
return -1;
325
+
}
326
+
if (!is_system_available) {
327
+
PE("System isn't available, devices won't be available!");
328
}
329
330
switch (op_mode) {
+11
src/xrt/targets/libmonado/monado.c
+11
src/xrt/targets/libmonado/monado.c
···
1
// Copyright 2019-2024, Collabora, Ltd.
2
+
// Copyright 2025, NVIDIA CORPORATION.
3
// SPDX-License-Identifier: BSL-1.0
4
/*!
5
* @file
···
146
PE("Connection init error '%i'!\n", xret);
147
free(r);
148
return MND_ERROR_CONNECTING_FAILED;
149
+
}
150
+
151
+
bool is_system_available = false;
152
+
xret = ipc_call_instance_is_system_available(&r->ipc_c, &is_system_available);
153
+
if (xret != XRT_SUCCESS) {
154
+
PE("ipc_call_instance_is_system_available: '%i'!\n", xret);
155
+
return -1;
156
+
}
157
+
if (!is_system_available) {
158
+
PE("System isn't available, devices won't be available!");
159
}
160
161
*out_root = r;
+28
-19
src/xrt/targets/sdl_test/sdl_compositor.c
+28
-19
src/xrt/targets/sdl_test/sdl_compositor.c
···
43
return &c->base.vk;
44
}
45
46
-
#define SC_TRACE(c, ...) U_LOG_IFL_T(c->base.vk.log_level, __VA_ARGS__);
47
-
#define SC_DEBUG(c, ...) U_LOG_IFL_D(c->base.vk.log_level, __VA_ARGS__);
48
-
#define SC_INFO(c, ...) U_LOG_IFL_I(c->base.vk.log_level, __VA_ARGS__);
49
-
#define SC_WARN(c, ...) U_LOG_IFL_W(c->base.vk.log_level, __VA_ARGS__);
50
-
#define SC_ERROR(c, ...) U_LOG_IFL_E(c->base.vk.log_level, __VA_ARGS__);
51
52
53
/*
···
246
struct comp_vulkan_formats formats = {0};
247
comp_vulkan_formats_check(vk, &formats);
248
comp_vulkan_formats_copy_to_info(&formats, info);
249
-
comp_vulkan_formats_log(c->base.vk.log_level, &formats);
250
251
return true;
252
}
···
256
{
257
struct xrt_system_compositor_info *sys_info = &c->sys_info;
258
259
-
// Required by OpenXR spec.
260
sys_info->max_layers = XRT_MAX_LAYERS;
261
262
// UUIDs and LUID already set in vk init.
···
277
}
278
279
// clang-format off
280
-
sys_info->views[0].recommended.width_pixels = w;
281
-
sys_info->views[0].recommended.height_pixels = h;
282
-
sys_info->views[0].recommended.sample_count = 1;
283
-
sys_info->views[0].max.width_pixels = max;
284
-
sys_info->views[0].max.height_pixels = max;
285
-
sys_info->views[0].max.sample_count = 1;
286
287
-
sys_info->views[1].recommended.width_pixels = min; // Second view is minimum
288
-
sys_info->views[1].recommended.height_pixels = min; // Second view is minimum
289
-
sys_info->views[1].recommended.sample_count = 1;
290
-
sys_info->views[1].max.width_pixels = max;
291
-
sys_info->views[1].max.height_pixels = max;
292
-
sys_info->views[1].max.sample_count = 1;
293
// clang-format on
294
295
// Copy the list directly.
···
43
return &c->base.vk;
44
}
45
46
+
#define SC_TRACE(c, ...) U_LOG_IFL_T(get_vk(c)->log_level, __VA_ARGS__);
47
+
#define SC_DEBUG(c, ...) U_LOG_IFL_D(get_vk(c)->log_level, __VA_ARGS__);
48
+
#define SC_INFO(c, ...) U_LOG_IFL_I(get_vk(c)->log_level, __VA_ARGS__);
49
+
#define SC_WARN(c, ...) U_LOG_IFL_W(get_vk(c)->log_level, __VA_ARGS__);
50
+
#define SC_ERROR(c, ...) U_LOG_IFL_E(get_vk(c)->log_level, __VA_ARGS__);
51
52
53
/*
···
246
struct comp_vulkan_formats formats = {0};
247
comp_vulkan_formats_check(vk, &formats);
248
comp_vulkan_formats_copy_to_info(&formats, info);
249
+
comp_vulkan_formats_log(vk->log_level, &formats);
250
251
return true;
252
}
···
256
{
257
struct xrt_system_compositor_info *sys_info = &c->sys_info;
258
259
+
/*
260
+
* Required by OpenXR spec (minimum 16).
261
+
*
262
+
* NOTE: When using Vulkan compositor components (c/render, c/util),
263
+
* call render_max_layers_capable() to clamp this value based on
264
+
* actual device limits.
265
+
*/
266
sys_info->max_layers = XRT_MAX_LAYERS;
267
268
// UUIDs and LUID already set in vk init.
···
283
}
284
285
// clang-format off
286
+
sys_info->view_configs[0].view_type = XRT_VIEW_TYPE_STEREO;
287
+
sys_info->view_configs[0].view_count = 2;
288
+
289
+
sys_info->view_configs[0].views[0].recommended.width_pixels = w;
290
+
sys_info->view_configs[0].views[0].recommended.height_pixels = h;
291
+
sys_info->view_configs[0].views[0].recommended.sample_count = 1;
292
+
sys_info->view_configs[0].views[0].max.width_pixels = max;
293
+
sys_info->view_configs[0].views[0].max.height_pixels = max;
294
+
sys_info->view_configs[0].views[0].max.sample_count = 1;
295
296
+
sys_info->view_configs[0].views[1].recommended.width_pixels = min; // Second view is minimum
297
+
sys_info->view_configs[0].views[1].recommended.height_pixels = min; // Second view is minimum
298
+
sys_info->view_configs[0].views[1].recommended.sample_count = 1;
299
+
sys_info->view_configs[0].views[1].max.width_pixels = max;
300
+
sys_info->view_configs[0].views[1].max.height_pixels = max;
301
+
sys_info->view_configs[0].views[1].max.sample_count = 1;
302
// clang-format on
303
304
// Copy the list directly.
+4
src/xrt/targets/service/main.c
+4
src/xrt/targets/service/main.c
···
11
12
#include "xrt/xrt_config_os.h"
13
14
#include "util/u_metrics.h"
15
#include "util/u_logging.h"
16
#include "util/u_trace_marker.h"
···
22
#include "server/ipc_server_interface.h"
23
24
#include "target_lists.h"
25
26
27
// Insert the on load constructor to init trace marker.
···
44
.window_title = "Monado! โจโก๐ฅ",
45
.open = U_DEBUG_GUI_OPEN_AUTO,
46
},
47
};
48
49
int ret = ipc_server_main(argc, argv, &ismi);
···
11
12
#include "xrt/xrt_config_os.h"
13
14
+
#include "util/u_debug.h"
15
#include "util/u_metrics.h"
16
#include "util/u_logging.h"
17
#include "util/u_trace_marker.h"
···
23
#include "server/ipc_server_interface.h"
24
25
#include "target_lists.h"
26
+
27
+
DEBUG_GET_ONCE_BOOL_OPTION(exit_on_disconnect, "IPC_EXIT_ON_DISCONNECT", false)
28
29
30
// Insert the on load constructor to init trace marker.
···
47
.window_title = "Monado! โจโก๐ฅ",
48
.open = U_DEBUG_GUI_OPEN_AUTO,
49
},
50
+
.exit_on_disconnect = debug_get_bool_option_exit_on_disconnect(),
51
};
52
53
int ret = ipc_server_main(argc, argv, &ismi);
+14
src/xrt/targets/service-lib/service_target.cpp
+14
src/xrt/targets/service-lib/service_target.cpp
···
78
// No-op
79
}
80
81
+
static void
82
+
signalClientConnectedTrampoline(struct ipc_server *s, uint32_t client_id, void *data)
83
+
{
84
+
// No-op
85
+
}
86
+
87
+
static void
88
+
signalClientDisconnectedTrampoline(struct ipc_server *s, uint32_t client_id, void *data)
89
+
{
90
+
// No-op
91
+
}
92
+
93
int32_t
94
addClient(int fd)
95
{
···
152
.init_failed = signalInitFailed,
153
.mainloop_entering = signalStartupCompleteTrampoline,
154
.mainloop_leaving = signalShuttingDownTrampoline,
155
+
.client_connected = signalClientConnectedTrampoline,
156
+
.client_disconnected = signalClientDisconnectedTrampoline,
157
};
158
159
//! Reference to the ipc_server, managed by ipc_server_process
-1
src/xrt/tracking/hand/mercury/hg_sync.cpp
-1
src/xrt/tracking/hand/mercury/hg_sync.cpp
+4
-10
src/xrt/tracking/hand/t_hand_tracking_async.c
+4
-10
src/xrt/tracking/hand/t_hand_tracking_async.c
···
137
struct xrt_space_relation wrist_rel =
138
hta->working.hands[i].values.hand_joint_set_default[XRT_HAND_JOINT_WRIST].relation;
139
140
-
m_relation_history_estimate_motion( //
141
-
hta->present.relation_hist[i], //
142
-
&wrist_rel, //
143
-
hta->working.timestamp, //
144
-
&wrist_rel); //
145
-
146
-
m_relation_history_push( //
147
-
hta->present.relation_hist[i], //
148
-
&wrist_rel, //
149
-
hta->working.timestamp); //
150
}
151
152
hta->hand_tracking_work_active = false;
···
137
struct xrt_space_relation wrist_rel =
138
hta->working.hands[i].values.hand_joint_set_default[XRT_HAND_JOINT_WRIST].relation;
139
140
+
m_relation_history_push_with_motion_estimation( //
141
+
hta->present.relation_hist[i], //
142
+
&wrist_rel, //
143
+
hta->working.timestamp); //
144
}
145
146
hta->hand_tracking_work_active = false;
+7
-1
tests/CMakeLists.txt
+7
-1
tests/CMakeLists.txt
···
27
list(APPEND tests tests_aux_d3d_d3d11 tests_comp_client_d3d11)
28
endif()
29
if(XRT_HAVE_D3D12)
30
-
list(APPEND tests tests_comp_client_d3d12)
31
endif()
32
if(XRT_HAVE_VULKAN)
33
list(APPEND tests tests_comp_client_vulkan tests_uv_to_tangent)
···
52
target_link_libraries(${testname} PRIVATE xrt-external-catch2)
53
target_link_libraries(${testname} PRIVATE aux_util)
54
add_test(NAME ${testname} COMMAND ${testname} --success --allow-running-no-tests)
55
endforeach()
56
57
# For tests that require more than just aux_util, link those other libs down here.
···
86
endif()
87
88
if(XRT_HAVE_D3D12)
89
target_link_libraries(tests_comp_client_d3d12 PRIVATE comp_client comp_mock)
90
endif()
91
···
111
if(XRT_HAVE_VULKAN AND XRT_HAVE_D3D11)
112
target_link_libraries(tests_aux_d3d_d3d11 PRIVATE comp_util aux_vk)
113
endif()
···
27
list(APPEND tests tests_aux_d3d_d3d11 tests_comp_client_d3d11)
28
endif()
29
if(XRT_HAVE_D3D12)
30
+
list(APPEND tests tests_aux_d3d_d3d12 tests_comp_client_d3d12)
31
endif()
32
if(XRT_HAVE_VULKAN)
33
list(APPEND tests tests_comp_client_vulkan tests_uv_to_tangent)
···
52
target_link_libraries(${testname} PRIVATE xrt-external-catch2)
53
target_link_libraries(${testname} PRIVATE aux_util)
54
add_test(NAME ${testname} COMMAND ${testname} --success --allow-running-no-tests)
55
+
set_target_properties(${testname} PROPERTIES FOLDER monado_tests)
56
endforeach()
57
58
# For tests that require more than just aux_util, link those other libs down here.
···
87
endif()
88
89
if(XRT_HAVE_D3D12)
90
+
target_link_libraries(tests_aux_d3d_d3d12 PRIVATE aux_d3d)
91
target_link_libraries(tests_comp_client_d3d12 PRIVATE comp_client comp_mock)
92
endif()
93
···
113
if(XRT_HAVE_VULKAN AND XRT_HAVE_D3D11)
114
target_link_libraries(tests_aux_d3d_d3d11 PRIVATE comp_util aux_vk)
115
endif()
116
+
117
+
if(XRT_HAVE_VULKAN AND XRT_HAVE_D3D12)
118
+
target_link_libraries(tests_aux_d3d_d3d12 PRIVATE comp_util aux_vk)
119
+
endif()
+13
-15
tests/tests_aux_d3d_d3d11.cpp
+13
-15
tests/tests_aux_d3d_d3d11.cpp
···
88
std::vector<xrt_image_native> xins;
89
xins.reserve(image_count);
90
91
-
// Keep this around until after successful import, then detach all.
92
-
std::vector<wil::unique_handle> handlesForImport;
93
-
handlesForImport.reserve(image_count);
94
-
95
for (HANDLE handle : handles) {
96
-
wil::unique_handle duped{u_graphics_buffer_ref(handle)};
97
xrt_image_native xin;
98
-
xin.handle = duped.get();
99
xin.size = 0;
100
xin.use_dedicated_allocation = use_dedicated_allocation;
101
102
-
handlesForImport.emplace_back(std::move(duped));
103
xins.emplace_back(xin);
104
}
105
106
// Import into a vulkan image collection
107
-
bool result = VK_SUCCESS == vk_ic_from_natives(vk, &vk_info, xins.data(), (uint32_t)xins.size(), vkic.get());
108
109
-
if (result) {
110
-
// The imported swapchain took ownership of them now, release them from ownership here.
111
-
for (auto &h : handlesForImport) {
112
-
h.release();
113
-
}
114
-
}
115
-
return result;
116
}
117
#else
118
···
88
std::vector<xrt_image_native> xins;
89
xins.reserve(image_count);
90
91
for (HANDLE handle : handles) {
92
+
/*!
93
+
* If shared resources have been allocated without using NT handles we can't use DuplicateHandle
94
+
*(like u_graphics_buffer_ref does internally) or CloseHandle (which wil::~unique_handle will call).
95
+
* More info:
96
+
* https://learn.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgiresource-getsharedhandle#remarks
97
+
* When using KMT handles, their validity is tied to the underlying video memory (I guess that means a
98
+
* ID3D11Texture2D object).
99
+
*/
100
xrt_image_native xin;
101
+
xin.handle = handle;
102
xin.size = 0;
103
xin.use_dedicated_allocation = use_dedicated_allocation;
104
+
xin.is_dxgi_handle = true;
105
106
xins.emplace_back(xin);
107
}
108
109
// Import into a vulkan image collection
110
+
const VkResult ret = vk_ic_from_natives(vk, &vk_info, xins.data(), (uint32_t)xins.size(), vkic.get());
111
+
VK_CHK_WITH_RET(ret, "vk_ic_from_natives", false);
112
113
+
return true;
114
}
115
#else
116
+201
tests/tests_aux_d3d_d3d12.cpp
+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
+
}