Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for OpenXR #1129

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
5987480
ports: Add jsoncpp.
lubosz May 25, 2024
bba3f07
ports: Add openxr-loader.
lubosz May 25, 2024
beec26c
Camera: Init default values.
lubosz Feb 26, 2024
3d7c44c
UserInputMapper: Make error an error.
lubosz Mar 2, 2024
d1c8746
HmdDisplayPlugin: Fix whitespace.
lubosz Feb 24, 2024
c42a612
Context: Maintain orientation of eye offset matrix.
lubosz Mar 10, 2024
abf9c38
Application: Maintain orientation of eye offset matrix.
lubosz Mar 10, 2024
03b8a8c
Application: Improve scoping.
lubosz Mar 10, 2024
692bddb
plugins: Add OpenXR plugin.
lubosz Feb 12, 2024
6104de9
OpenXrContext: Improve errors when runtime is not available.
lubosz Mar 14, 2024
1dafc89
OpenGlDisplayPlugin: Add possibility to present frames only once.
lubosz Mar 16, 2024
bfbd1e7
OpenXrInput: Improve mapping for the Index controller.
lubosz Mar 13, 2024
8976a82
controllers: openxr: Use actions for walking.
lubosz Mar 17, 2024
5803072
controllers: Improve openxr_index.json mapping.
lubosz Mar 17, 2024
68dcd78
OpenXrInputPlugin: Improve haptic feedback mapping.
lubosz Mar 17, 2024
8a8b7dd
OpenXrContext: Add Windows platform and bindings.
lubosz Mar 17, 2024
07da25f
OpenXr: Enable C++20 for OpenXR plugin.
JulianGro Jul 7, 2024
2104de4
GLMHelpers: Fix build with C++20 on GCC.
lubosz Sep 3, 2024
bf64af0
OpenXr: Platform improvements.
HifiExperiments Aug 10, 2024
b351af1
OpenXr: Use C++20 std::optional.
lubosz Sep 4, 2024
11b2e3d
OpenXrInputPlugin: Use C++20 map iterators.
lubosz Sep 4, 2024
74145cb
OpenXrDisplayPlugin: Use C++20 std::format.
lubosz Sep 4, 2024
4db7e1a
Install missing xcb/glx.h dependency.
JulianGro Sep 5, 2024
32aff01
pr_build: Get GCC 13 on Ubuntu using the ppa:ubuntu-toolchain-r/test.
lubosz Sep 7, 2024
92ab06e
Make sure add-apt-repository is available.
JulianGro Sep 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion .github/workflows/pr_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ jobs:
runner: [self_hosted, type-cx52, image-x86-app-docker-ce]
arch: amd64
build_type: full
apt-dependencies: pkg-config libxext-dev libdouble-conversion-dev libpcre2-16-0 libpulse0 libharfbuzz-dev libnss3 libnspr4 libxdamage1 libasound2 # add missing dependencies to docker image when convenient
apt-dependencies: pkg-config libxext-dev libdouble-conversion-dev libpcre2-16-0 libpulse0 libharfbuzz-dev libnss3 libnspr4 libxdamage1 libasound2 libxcb-glx0-dev # add missing dependencies to docker image when convenient
image: docker.io/overte/overte-full-build:0.1.1-ubuntu-20.04-amd64
# Android builds are currently failing
#- os: ubuntu-18.04
Expand All @@ -75,6 +75,7 @@ jobs:
runner: [self_hosted, type-cax41, image-arm-app-docker-ce]
arch: aarch64
build_type: full
apt-dependencies: libxcb-glx0-dev # add missing dependencies to docker image when convenient
image: docker.io/overte/overte-full-build:0.1.1-ubuntu-22.04-aarch64
fail-fast: false
runs-on: ${{matrix.runner}}
Expand Down Expand Up @@ -189,6 +190,16 @@ jobs:
echo "Installing apt packages"
sudo apt install -y ${{ matrix.apt-dependencies }} || exit 1

echo "Adding Toolchain test PPA"
apt install -y software-properties-common
add-apt-repository ppa:ubuntu-toolchain-r/test

echo "Installing gcc-13"
apt install -y gcc-13 g++-13 || exit 1

# Set GCC 13 as default
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 100 --slave /usr/bin/g++ g++ /usr/bin/g++-13 --slave /usr/bin/gcov gcov /usr/bin/gcov-13

else # macOS
echo "Downloading MacOSX10.12 SDK.."
curl --progress-bar -L -o macOS_SDK10.12.4.tar.xz "https://data.moto9000.moe/overte_packages/macOS_SDK10.12.4.tar.xz" || exit 1
Expand Down
2 changes: 1 addition & 1 deletion cmake/ports/hifi-client-deps/CONTROL
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Source: hifi-client-deps
Version: 0.1
Description: Collected dependencies for High Fidelity applications
Build-Depends: hifi-deps, aristo (windows), glslang, liblo (windows), nlohmann-json, openvr ((linux&!arm)|windows), quazip (!android), sdl2 (!android), spirv-cross (!android), spirv-tools (!android), sranipal (windows), vulkanmemoryallocator, discord-rpc (!android)
Build-Depends: hifi-deps, aristo (windows), glslang, liblo (windows), nlohmann-json, openvr ((linux&!arm)|windows), openxr-loader, quazip (!android), sdl2 (!android), spirv-cross (!android), spirv-tools (!android), sranipal (windows), vulkanmemoryallocator, discord-rpc (!android)
34 changes: 34 additions & 0 deletions cmake/ports/jsoncpp/portfile.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
vcpkg_from_github(
OUT_SOURCE_PATH SOURCE_PATH
REPO open-source-parsers/jsoncpp
REF "${VERSION}"
SHA512 1d06e044759b1e1a4cc4960189dd7e001a0a4389d7239a6d59295af995a553518e4e0337b4b4b817e70da5d9731a4c98655af90791b6287870b5ff8d73ad8873
HEAD_REF master
)

string(COMPARE EQUAL "${VCPKG_LIBRARY_LINKAGE}" "static" JSONCPP_STATIC)
string(COMPARE EQUAL "${VCPKG_CRT_LINKAGE}" "static" STATIC_CRT)

vcpkg_cmake_configure(
SOURCE_PATH "${SOURCE_PATH}"
OPTIONS
-DJSONCPP_WITH_CMAKE_PACKAGE=ON
-DBUILD_STATIC_LIBS=${JSONCPP_STATIC}
-DJSONCPP_STATIC_WINDOWS_RUNTIME=${STATIC_CRT}
-DJSONCPP_WITH_PKGCONFIG_SUPPORT=ON
-DJSONCPP_WITH_POST_BUILD_UNITTEST=OFF
-DJSONCPP_WITH_TESTS=OFF
-DJSONCPP_WITH_EXAMPLE=OFF
-DBUILD_OBJECT_LIBS=OFF
)

vcpkg_cmake_install()

vcpkg_cmake_config_fixup(CONFIG_PATH lib/cmake/jsoncpp)

file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include")

vcpkg_copy_pdbs()
vcpkg_fixup_pkgconfig()

vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE")
18 changes: 18 additions & 0 deletions cmake/ports/jsoncpp/vcpkg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "jsoncpp",
"version": "1.9.5",
"port-version": 4,
"description": "JsonCpp is a C++ library that allows manipulating JSON values, including serialization and deserialization to and from strings. It can also preserve existing comment in unserialization/serialization steps, making it a convenient format to store user input files.",
"homepage": "https://github.com/open-source-parsers/jsoncpp",
"license": "MIT",
"dependencies": [
{
"name": "vcpkg-cmake",
"host": true
},
{
"name": "vcpkg-cmake-config",
"host": true
}
]
}
23 changes: 23 additions & 0 deletions cmake/ports/openxr-loader/fix-jinja2.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
From d80c7dc3f4810fc49e4444590d39ef71e8a9b01c Mon Sep 17 00:00:00 2001
From: Adam Johnson <[email protected]>
Date: Sat, 19 Feb 2022 19:42:31 -0500
Subject: [PATCH] Fix bad import in jinja2

---
external/python/jinja2/utils.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/external/python/jinja2/utils.py b/external/python/jinja2/utils.py
index db9c5d06..f198e3ef 100644
--- a/external/python/jinja2/utils.py
+++ b/external/python/jinja2/utils.py
@@ -639,4 +639,8 @@ def __repr__(self):


# Imported here because that's where it was in the past
-from markupsafe import Markup, escape, soft_unicode
+from markupsafe import Markup, escape
+try:
+ from markupsafe import soft_unicode
+except ImportError:
+ from markupsafe import soft_str as soft_unicode
30 changes: 30 additions & 0 deletions cmake/ports/openxr-loader/fix-openxr-sdk-jsoncpp.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index c75b145..386494c 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -89,7 +89,7 @@ if(NOT VULKAN_INCOMPATIBLE)
endif()

find_package(Threads REQUIRED)
-find_package(JsonCpp)
+find_package(jsoncpp CONFIG REQUIRED)

### All options defined here
option(BUILD_LOADER "Build loader" ON)
diff --git a/src/loader/CMakeLists.txt b/src/loader/CMakeLists.txt
index 6a88cf4..0821a3d 100644
--- a/src/loader/CMakeLists.txt
+++ b/src/loader/CMakeLists.txt
@@ -68,7 +68,11 @@ add_library(openxr_loader ${LIBRARY_TYPE}
${openxr_loader_RESOURCE_FILE}
)
if(BUILD_WITH_SYSTEM_JSONCPP)
- target_link_libraries(openxr_loader PRIVATE JsonCpp::JsonCpp)
+ if(BUILD_SHARED_LIBS)
+ target_link_libraries(openxr_loader PRIVATE jsoncpp_lib)
+ else()
+ target_link_libraries(openxr_loader PRIVATE jsoncpp_static)
+ endif()
else()
target_sources(openxr_loader
PRIVATE
79 changes: 79 additions & 0 deletions cmake/ports/openxr-loader/portfile.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@

vcpkg_from_github(
OUT_SOURCE_PATH SOURCE_PATH
REPO KhronosGroup/OpenXR-SDK
REF "release-${VERSION}"
SHA512 6efc7596e707f95366dbcdbac9bd7d0c20735a2175b4edf56a9e8a112cf0ab8b664069fe942313164a37119032ddbf5671bc88ab5f276005dd36e4a4dabba1c7
HEAD_REF master
PATCHES
fix-openxr-sdk-jsoncpp.patch
)

vcpkg_from_github(
OUT_SOURCE_PATH SDK_SOURCE_PATH
REPO KhronosGroup/OpenXR-SDK-Source
REF "release-${VERSION}"
SHA512 04bdb0f16078209b5edd175a3396f70e1ceb8cfa382c65b8fda388e565480e3844daf68e0d987e72ed8c21d3148af0b41a2170911ec1660565887e0e5ae6d2bf
HEAD_REF master
PATCHES
fix-openxr-sdk-jsoncpp.patch
fix-jinja2.patch
)

vcpkg_from_github(
OUT_SOURCE_PATH HPP_SOURCE_PATH
REPO KhronosGroup/OpenXR-hpp
REF 63db9919822f8af6f7bf7416ba6a015d4617202e
SHA512 9e768f485d1631f8e74f35f028a64e2d64e33d362c53ae1c54427a10786e3befdd24089927319aa1a4b4c3e010247bd6cb3394bcee460c467c637ab6bc7bec90
HEAD_REF master
PATCHES
python3_8_compatibility.patch
)

# Weird behavior inside the OpenXR loader. On Windows they force shared libraries to use static crt, and
# vice-versa. Might be better in future iterations to patch the CMakeLists.txt for OpenXR
if (VCPKG_TARGET_IS_UWP OR VCPKG_TARGET_IS_WINDOWS)
if(VCPKG_LIBRARY_LINKAGE STREQUAL static)
set(DYNAMIC_LOADER OFF)
set(VCPKG_CRT_LINKAGE dynamic)
else()
set(DYNAMIC_LOADER ON)
set(VCPKG_CRT_LINKAGE static)
endif()
endif()

vcpkg_find_acquire_program(PYTHON3)

vcpkg_cmake_configure(
SOURCE_PATH "${SOURCE_PATH}"
OPTIONS
-DBUILD_API_LAYERS=OFF
-DBUILD_TESTS=OFF
-DBUILD_CONFORMANCE_TESTS=OFF
-DDYNAMIC_LOADER=${DYNAMIC_LOADER}
-DPYTHON_EXECUTABLE="${PYTHON3}"
-DBUILD_WITH_SYSTEM_JSONCPP=ON
)

vcpkg_cmake_install()

# Generate the OpenXR C++ bindings
set(ENV{OPENXR_REPO} "${SDK_SOURCE_PATH}")
vcpkg_execute_required_process(
COMMAND ${PYTHON3} "${HPP_SOURCE_PATH}/scripts/hpp_genxr.py" -quiet -registry "${SDK_SOURCE_PATH}/specification/registry/xr.xml" -o "${CURRENT_PACKAGES_DIR}/include/openxr"
WORKING_DIRECTORY "${HPP_SOURCE_PATH}"
LOGNAME "openxr-hpp"
)

if(VCPKG_TARGET_IS_WINDOWS)
vcpkg_cmake_config_fixup(PACKAGE_NAME OpenXR CONFIG_PATH cmake)
else()
vcpkg_cmake_config_fixup(PACKAGE_NAME OpenXR CONFIG_PATH lib/cmake/openxr)
endif()

file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include")
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/share")

vcpkg_fixup_pkgconfig()
vcpkg_copy_pdbs()
file(INSTALL "${SOURCE_PATH}/LICENSE" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" RENAME copyright)
13 changes: 13 additions & 0 deletions cmake/ports/openxr-loader/python3_8_compatibility.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
diff --git a/scripts/hpp_genxr.py b/scripts/hpp_genxr.py
index ce419b0..23e1d3d 100644
--- a/scripts/hpp_genxr.py
+++ b/scripts/hpp_genxr.py
@@ -36,7 +36,7 @@ from xrconventions import OpenXRConventions
from data import EXCLUDED_EXTENSIONS


-def makeREstring(strings: Iterable[str], default: typing.Optional[str] = None) -> str:
+def makeREstring(strings, default: typing.Optional[str] = None) -> str:
"""Turn a list of strings into a regexp string matching exactly those strings."""
if strings or default is None:
return f"^({'|'.join(re.escape(s) for s in strings)})$"
27 changes: 27 additions & 0 deletions cmake/ports/openxr-loader/vcpkg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "openxr-loader",
"version": "1.0.31",
"description": "A royalty-free, open standard that provides high-performance access to Augmented Reality (AR) and Virtual Reality (VR)—collectively known as XR—platforms and devices",
"homepage": "https://github.com/KhronosGroup/OpenXR-SDK",
"license": "Apache-2.0",
"supports": "!uwp & !osx",
"dependencies": [
"jsoncpp",
{
"name": "vcpkg-cmake",
"host": true
},
{
"name": "vcpkg-cmake-config",
"host": true
}
],
"features": {
"vulkan": {
"description": "Vulkan functionality for OpenXR",
"dependencies": [
"vulkan"
]
}
}
}
35 changes: 35 additions & 0 deletions interface/resources/controllers/openxr_index.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "OpenXR Index to Actions",
"channels": [
{ "from": "Index.LeftHand", "to": "Standard.LeftHand" },
{ "from": "Index.RightHand", "to": "Standard.RightHand" },
{ "from": "Index.Head", "to" : "Standard.Head", "when" : [ "Application.InHMD"] },

{ "from": "Index.LeftPrimaryThumb", "to": "Actions.Down" },
{ "from": "Index.LeftPrimaryThumbTouch", "to": "Standard.LeftPrimaryThumbTouch" },
{ "from": "Index.LeftSecondaryThumb", "to": "Actions.ContextMenu" },
{ "from": "Index.LeftSecondaryThumbTouch", "to": "Standard.LeftSecondaryThumbTouch" },

{ "from": "Index.RightPrimaryThumb", "to": "Actions.Up" },
{ "from": "Index.RightPrimaryThumbTouch", "to": "Standard.RightPrimaryThumbTouch" },
{ "from": "Index.RightSecondaryThumb", "to": "Actions.Sprint" },
{ "from": "Index.RightSecondaryThumbTouch", "to": "Standard.RightSecondaryThumbTouch" },

{ "from": "Index.LY", "to": "Actions.TranslateZ", "filters": ["invert"] },
{ "from": "Index.LX", "to": "Actions.TranslateX" },
{ "from": "Index.RY", "to": "Standard.RY" },
{ "from": "Index.RX", "to": "Standard.RX" },
{ "from": "Index.LS", "to": "Standard.LS" },
{ "from": "Index.RS", "to": "Actions.CycleCamera" },
{ "from": "Index.LSTouch", "to": "Standard.LSTouch" },
{ "from": "Index.RSTouch", "to": "Standard.RSTouch" },

{ "from": "Index.RT", "to": "Standard.RT" },
{ "from": "Index.LT", "to": "Standard.LT" },
{ "from": "Index.RTClick", "to": "Standard.RTClick" },
{ "from": "Index.LTClick", "to": "Standard.LTClick" },

{ "from": "Index.LeftPrimaryIndexTouch", "to": "Standard.LeftPrimaryIndexTouch" },
{ "from": "Index.RightPrimaryIndexTouch", "to": "Standard.RightPrimaryIndexTouch" }
]
}
67 changes: 28 additions & 39 deletions interface/src/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6942,51 +6942,40 @@ void Application::updateRenderArgs(float deltaTime) {
appRenderArgs._eyeToWorld = _myCamera.getTransform();
appRenderArgs._isStereo = false;

{
if (getActiveDisplayPlugin()->isStereo()) {
auto hmdInterface = DependencyManager::get<HMDScriptingInterface>();
float ipdScale = hmdInterface->getIPDScale();

// scale IPD by sensorToWorldScale, to make the world seem larger or smaller accordingly.
ipdScale *= sensorToWorldScale;
float ipdScale = hmdInterface->getIPDScale() * sensorToWorldScale;

auto baseProjection = appRenderArgs._renderArgs.getViewFrustum().getProjection();

if (getActiveDisplayPlugin()->isStereo()) {
// Stereo modes will typically have a larger projection matrix overall,
// so we ask for the 'mono' projection matrix, which for stereo and HMD
// plugins will imply the combined projection for both eyes.
//
// This is properly implemented for the Oculus plugins, but for OpenVR
// and Stereo displays I'm not sure how to get / calculate it, so we're
// just relying on the left FOV in each case and hoping that the
// overall culling margin of error doesn't cause popping in the
// right eye. There are FIXMEs in the relevant plugins
_myCamera.setProjection(getActiveDisplayPlugin()->getCullingProjection(baseProjection));
appRenderArgs._isStereo = true;

auto& eyeOffsets = appRenderArgs._eyeOffsets;
auto& eyeProjections = appRenderArgs._eyeProjections;

// FIXME we probably don't need to set the projection matrix every frame,
// only when the display plugin changes (or in non-HMD modes when the user
// changes the FOV manually, which right now I don't think they can.
for_each_eye([&](Eye eye) {
// For providing the stereo eye views, the HMD head pose has already been
// applied to the avatar, so we need to get the difference between the head
// pose applied to the avatar and the per eye pose, and use THAT as
// the per-eye stereo matrix adjustment.
mat4 eyeToHead = getActiveDisplayPlugin()->getEyeToHeadTransform(eye);
// Grab the translation
vec3 eyeOffset = glm::vec3(eyeToHead[3]);
// Apply IPD scaling
mat4 eyeOffsetTransform = glm::translate(mat4(), eyeOffset * -1.0f * ipdScale);
eyeOffsets[eye] = eyeOffsetTransform;
eyeProjections[eye] = getActiveDisplayPlugin()->getEyeProjection(eye, baseProjection);
});
// Stereo modes will typically have a larger projection matrix overall,
// so we ask for the 'mono' projection matrix, which for stereo and HMD
// plugins will imply the combined projection for both eyes.
//
// This is properly implemented for the Oculus plugins, but for OpenVR
// and Stereo displays I'm not sure how to get / calculate it, so we're
// just relying on the left FOV in each case and hoping that the
// overall culling margin of error doesn't cause popping in the
// right eye. There are FIXMEs in the relevant plugins
_myCamera.setProjection(getActiveDisplayPlugin()->getCullingProjection(baseProjection));
appRenderArgs._isStereo = true;

auto& eyeOffsets = appRenderArgs._eyeOffsets;
auto& eyeProjections = appRenderArgs._eyeProjections;

// FIXME we probably don't need to set the projection matrix every frame,
// only when the display plugin changes (or in non-HMD modes when the user
// changes the FOV manually, which right now I don't think they can.
for_each_eye([&](Eye eye) {
eyeOffsets[eye] = getActiveDisplayPlugin()->getEyeToHeadTransform(eye);
// Apply IPD scaling
eyeOffsets[eye][3][0] *= ipdScale;
eyeProjections[eye] = getActiveDisplayPlugin()->getEyeProjection(eye, baseProjection);
});

// Configure the type of display / stereo
appRenderArgs._renderArgs._displayMode = (isHMDMode() ? RenderArgs::STEREO_HMD : RenderArgs::STEREO_MONITOR);
}
// Configure the type of display / stereo
appRenderArgs._renderArgs._displayMode = (isHMDMode() ? RenderArgs::STEREO_HMD : RenderArgs::STEREO_MONITOR);
}

appRenderArgs._renderArgs._stencilMaskMode = getActiveDisplayPlugin()->getStencilMaskMode();
Expand Down
6 changes: 3 additions & 3 deletions libraries/controllers/src/controllers/UserInputMapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1195,9 +1195,9 @@ Mapping::Pointer UserInputMapper::parseMapping(const QString& json) {
QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8(), &error);
// check validity of the document
if (doc.isNull()) {
qCDebug(controllers) << "Invalid JSON...\n";
qCDebug(controllers) << error.errorString();
qCDebug(controllers) << "JSON was:\n" << json << Qt::endl;
qCCritical(controllers) << "Invalid JSON...\n";
qCCritical(controllers) << error.errorString();
qCCritical(controllers) << "JSON was:\n" << json << Qt::endl;
return Mapping::Pointer();
}

Expand Down
Loading
Loading