Commit 004b1b7f authored by Kevin Qin's avatar Kevin Qin Committed by Commit Bot

OpenXR Support Oculus Touch Controller

Current OpenXR runtime only supports microsoft motion controller and
Khronos simple controller. Add suggest interaction profile for Oculus
touch controller.

Fixed: 1033708
Change-Id: I6904a2335c50291b3b4338b2004d262fdb2772e2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1966354
Commit-Queue: Zheng Qin <zheqi@microsoft.com>
Reviewed-by: default avatarAlexander Cooper <alcooper@chromium.org>
Cr-Commit-Position: refs/heads/master@{#727479}
parent 938f826a
......@@ -231,6 +231,7 @@ if (enable_vr) {
"openxr/openxr_device.h",
"openxr/openxr_input_helper.cc",
"openxr/openxr_input_helper.h",
"openxr/openxr_interaction_profiles.h",
"openxr/openxr_path_helper.cc",
"openxr/openxr_path_helper.h",
"openxr/openxr_render_loop.cc",
......
This diff is collapsed.
......@@ -12,6 +12,7 @@
#include <vector>
#include "base/optional.h"
#include "device/vr/openxr/openxr_interaction_profiles.h"
#include "device/vr/openxr/openxr_path_helper.h"
#include "device/vr/openxr/openxr_util.h"
#include "device/vr/public/mojom/vr_service.mojom.h"
......@@ -20,28 +21,6 @@
namespace device {
constexpr uint32_t kAxisDimensions = 2;
enum class OpenXrHandednessType {
kLeft = 0,
kRight = 1,
kCount = 2,
};
enum class OpenXrButtonType {
kTrigger = 0,
kSqueeze = 1,
kTrackpad = 2,
kThumbstick = 3,
kMaxValue = 3,
};
enum class OpenXrAxisType {
kTrackpad = 0,
kThumbstick = 1,
kMaxValue = 1,
};
class OpenXrController {
public:
OpenXrController();
......@@ -60,7 +39,9 @@ class OpenXrController {
XrActionSet action_set() const { return action_set_; }
uint32_t GetId() const;
device::mojom::XRHandedness GetHandness() const;
XrPath interaction_profile() const { return interaction_profile_; }
OpenXrInteractionProfileType interaction_profile() const {
return interaction_profile_;
}
mojom::XRInputSourceDescriptionPtr GetDescription(
XrTime predicted_display_time);
......@@ -76,39 +57,24 @@ class OpenXrController {
XrResult UpdateInteractionProfile();
private:
// ActionButton struct is used to store all XrAction that is related to the
// button. For example, we may need to query the analog value for button press
// which require a seperate XrAction than the current boolean XrAction.
struct ActionButton {
XrAction press_action;
XrAction touch_action;
XrAction value_action;
ActionButton()
: press_action(XR_NULL_HANDLE),
touch_action(XR_NULL_HANDLE),
value_action(XR_NULL_HANDLE) {}
};
XrResult InitializeControllerActions();
XrResult SuggestMicrosoftMotionControllerBindings(
std::map<XrPath, std::vector<XrActionSuggestedBinding>>* bindings);
XrResult SuggestKHRSimpleControllerBindings(
std::map<XrPath, std::vector<XrActionSuggestedBinding>>* bindings);
XrResult InitializeControllerSpaces();
XrResult SuggestBindings(
std::map<XrPath, std::vector<XrActionSuggestedBinding>>* bindings) const;
XrResult CreateActionsForButton(OpenXrButtonType button_type);
XrResult CreateAction(XrActionType type,
const std::string& action_name,
XrAction* action);
XrResult CreateActionSpace(XrAction action, XrSpace* space);
XrResult SuggestInteractionProfileBindings(
XrResult SuggestActionBinding(
std::map<XrPath, std::vector<XrActionSuggestedBinding>>* bindings,
XrPath interaction_profile_path,
std::unordered_map<XrAction, std::string> action_binding_map);
XrAction action,
std::string binding_string) const;
base::Optional<gfx::Transform> GetPointerFromGripTransform(
XrTime predicted_display_time) const;
......@@ -178,9 +144,11 @@ class OpenXrController {
XrAction pointer_pose_action_;
XrSpace pointer_pose_space_;
XrPath interaction_profile_;
OpenXrInteractionProfileType interaction_profile_;
std::unordered_map<OpenXrButtonType, ActionButton> button_action_map_;
std::unordered_map<OpenXrButtonType,
std::unordered_map<OpenXrButtonActionType, XrAction>>
button_action_map_;
std::unordered_map<OpenXrAxisType, XrAction> axis_action_map_;
const OpenXRPathHelper* path_helper_;
......
......@@ -4,6 +4,8 @@
#include "device/vr/openxr/openxr_input_helper.h"
#include "base/stl_util.h"
#include "device/gamepad/public/cpp/gamepad.h"
#include "device/vr/openxr/openxr_util.h"
#include "device/vr/util/xr_standard_gamepad_builder.h"
......@@ -45,7 +47,6 @@ base::Optional<Gamepad> GetXrStandardGamepad(
controller.GetButton(OpenXrButtonType::kTrigger);
if (!trigger_button)
return base::nullopt;
builder.SetPrimaryButton(trigger_button.value());
base::Optional<GamepadButton> squeeze_button =
......@@ -60,7 +61,6 @@ base::Optional<Gamepad> GetXrStandardGamepad(
base::Optional<GamepadBuilder::ButtonData> trackpad_button_data =
GetAxisButtonData(OpenXrAxisType::kTrackpad, trackpad_button,
trackpad_axis);
if (trackpad_button_data)
builder.SetTouchpadData(trackpad_button_data.value());
......@@ -71,10 +71,24 @@ base::Optional<Gamepad> GetXrStandardGamepad(
base::Optional<GamepadBuilder::ButtonData> thumbstick_button_data =
GetAxisButtonData(OpenXrAxisType::kThumbstick, thumbstick_button,
thumbstick_axis);
if (thumbstick_button_data)
builder.SetThumbstickData(thumbstick_button_data.value());
base::Optional<GamepadButton> x_button =
controller.GetButton(OpenXrButtonType::kButton1);
if (x_button)
builder.AddOptionalButtonData(x_button.value());
base::Optional<GamepadButton> y_button =
controller.GetButton(OpenXrButtonType::kButton2);
if (y_button)
builder.AddOptionalButtonData(y_button.value());
base::Optional<GamepadButton> thumbrest_button =
controller.GetButton(OpenXrButtonType::kThumbrest);
if (thumbrest_button)
builder.AddOptionalButtonData(thumbrest_button.value());
return builder.GetGamepad();
}
......@@ -203,11 +217,18 @@ base::WeakPtr<OpenXRInputHelper> OpenXRInputHelper::GetWeakPtr() {
base::Optional<Gamepad> OpenXRInputHelper ::GetWebXRGamepad(
const OpenXrController& controller) {
if (controller.interaction_profile() ==
path_helper_->GetDeclaredPaths()
.microsoft_motion_controller_interaction_profile) {
return GetXrStandardGamepad(controller);
OpenXrInteractionProfileType cur_type = controller.interaction_profile();
for (auto& it : kOpenXrControllerInteractionProfiles) {
if (it.type == cur_type) {
if (it.mapping == GamepadMapping::kXrStandard) {
return GetXrStandardGamepad(controller);
} else {
// if mapping is kNone
return base::nullopt;
}
}
}
return base::nullopt;
}
......
......@@ -12,6 +12,7 @@
#include "base/optional.h"
#include "device/vr/openxr/openxr_controller.h"
#include "device/vr/openxr/openxr_interaction_profiles.h"
namespace device {
......
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef DEVICE_VR_OPENXR_OPENXR_INTERACTION_PROFILES_H_
#define DEVICE_VR_OPENXR_OPENXR_INTERACTION_PROFILES_H_
#include "base/stl_util.h"
#include "device/gamepad/public/cpp/gamepad.h"
#include "third_party/openxr/src/include/openxr/openxr.h"
namespace device {
constexpr size_t kMaxNumActionMaps = 3;
enum class OpenXrHandednessType {
kLeft = 0,
kRight = 1,
kCount = 2,
};
enum class OpenXrInteractionProfileType {
kMicrosoftMotion = 0,
kKHRSimple = 1,
kOculusTouch = 2,
kCount = 3,
};
enum class OpenXrButtonType {
kTrigger = 0,
kSqueeze = 1,
kTrackpad = 2,
kThumbstick = 3,
kThumbrest = 4,
kButton1 = 5,
kButton2 = 6,
kMaxValue = 6,
};
enum class OpenXrAxisType {
kTrackpad = 0,
kThumbstick = 1,
kMaxValue = 1,
};
enum class OpenXrButtonActionType {
kPress = 0,
kTouch = 1,
kValue = 2,
kCount = 3,
};
struct OpenXrButtonActionPathMap {
OpenXrButtonActionType type;
const char* const path;
};
struct OpenXrButtonPathMap {
OpenXrButtonType type;
OpenXrButtonActionPathMap action_maps[kMaxNumActionMaps];
size_t action_map_size;
};
struct OpenXrAxisPathMap {
OpenXrAxisType type;
const char* const path;
};
struct OpenXrControllerInteractionProfile {
OpenXrInteractionProfileType type;
const char* const path;
GamepadMapping mapping;
const char* const* const input_profiles;
const size_t profile_size;
const OpenXrButtonPathMap* left_button_maps;
size_t left_button_map_size;
const OpenXrButtonPathMap* right_button_maps;
size_t right_button_map_size;
const OpenXrAxisPathMap* axis_maps;
size_t axis_map_size;
};
// TODO(crbug.com/1017513)
// Currently Supports:
// Microsoft motion controller.
// Khronos simple controller.
// Oculus touch controller.
// Declare OpenXR input profile bindings for other runtimes when they become
// available.
constexpr const char* kMicrosoftMotionInputProfiles[] = {
"windows-mixed-reality", "generic-trigger-squeeze-touchpad-thumbstick"};
constexpr const char* kGenericButtonInputProfiles[] = {"generic-button"};
constexpr const char* kOculusTouchInputProfiles[] = {
"oculus-touch", "generic-trigger-squeeze-thumbstick"};
constexpr OpenXrButtonPathMap kMicrosoftMotionControllerButtonPathMaps[] = {
{OpenXrButtonType::kTrigger,
{
{OpenXrButtonActionType::kPress, "/input/trigger/value"},
{OpenXrButtonActionType::kValue, "/input/trigger/value"},
},
2},
{OpenXrButtonType::kSqueeze,
{{OpenXrButtonActionType::kPress, "/input/squeeze/click"}},
1},
{OpenXrButtonType::kThumbstick,
{{OpenXrButtonActionType::kPress, "/input/thumbstick/click"}},
1},
{OpenXrButtonType::kTrackpad,
{{OpenXrButtonActionType::kPress, "/input/trackpad/click"},
{OpenXrButtonActionType::kTouch, "/input/trackpad/touch"}},
2}};
constexpr OpenXrButtonPathMap kKronosSimpleControllerButtonPathMaps[] = {
{OpenXrButtonType::kTrigger,
{{OpenXrButtonActionType::kPress, "/input/select/click"}},
1},
};
constexpr OpenXrButtonPathMap kOculusTouchLeftControllerButtonPathMaps[] = {
{OpenXrButtonType::kTrigger,
{{OpenXrButtonActionType::kPress, "/input/trigger/value"},
{OpenXrButtonActionType::kValue, "/input/trigger/value"},
{OpenXrButtonActionType::kTouch, "/input/trigger/touch"}},
3},
{OpenXrButtonType::kSqueeze,
{{OpenXrButtonActionType::kPress, "/input/squeeze/value"},
{OpenXrButtonActionType::kValue, "/input/squeeze/value"}},
2},
{OpenXrButtonType::kThumbstick,
{{OpenXrButtonActionType::kPress, "/input/thumbstick/click"},
{OpenXrButtonActionType::kTouch, "/input/thumbstick/touch"}},
2},
{OpenXrButtonType::kThumbrest,
{{OpenXrButtonActionType::kTouch, "/input/thumbrest/touch"}},
1},
{OpenXrButtonType::kButton1,
{{OpenXrButtonActionType::kPress, "/input/x/click"},
{OpenXrButtonActionType::kTouch, "/input/x/touch"}},
2},
{OpenXrButtonType::kButton2,
{{OpenXrButtonActionType::kPress, "/input/y/click"},
{OpenXrButtonActionType::kTouch, "/input/y/touch"}},
2},
};
constexpr OpenXrButtonPathMap kOculusTouchRightControllerButtonPathMaps[] = {
{OpenXrButtonType::kTrigger,
{{OpenXrButtonActionType::kPress, "/input/trigger/value"},
{OpenXrButtonActionType::kValue, "/input/trigger/value"},
{OpenXrButtonActionType::kTouch, "/input/trigger/touch"}},
3},
{OpenXrButtonType::kSqueeze,
{{OpenXrButtonActionType::kPress, "/input/squeeze/value"},
{OpenXrButtonActionType::kValue, "/input/squeeze/value"}},
2},
{OpenXrButtonType::kThumbstick,
{{OpenXrButtonActionType::kPress, "/input/thumbstick/click"},
{OpenXrButtonActionType::kTouch, "/input/thumbstick/touch"}},
2},
{OpenXrButtonType::kThumbrest,
{{OpenXrButtonActionType::kTouch, "/input/thumbrest/touch"}},
1},
{OpenXrButtonType::kButton1,
{{OpenXrButtonActionType::kPress, "/input/a/click"},
{OpenXrButtonActionType::kTouch, "/input/a/touch"}},
2},
{OpenXrButtonType::kButton2,
{{OpenXrButtonActionType::kPress, "/input/b/click"},
{OpenXrButtonActionType::kTouch, "/input/b/touch"}},
2},
};
constexpr OpenXrAxisPathMap kMicrosoftMotionControllerAxisPathMaps[] = {
{OpenXrAxisType::kTrackpad, "/input/trackpad"},
{OpenXrAxisType::kThumbstick, "/input/thumbstick"},
};
constexpr OpenXrAxisPathMap kOculusTouchControllerAxisPathMaps[] = {
{OpenXrAxisType::kThumbstick, "/input/thumbstick"},
};
constexpr OpenXrControllerInteractionProfile
kMicrosoftMotionInteractionProfile = {
OpenXrInteractionProfileType::kMicrosoftMotion,
"/interaction_profiles/microsoft/motion_controller",
GamepadMapping::kXrStandard,
kMicrosoftMotionInputProfiles,
base::size(kMicrosoftMotionInputProfiles),
kMicrosoftMotionControllerButtonPathMaps,
base::size(kMicrosoftMotionControllerButtonPathMaps),
kMicrosoftMotionControllerButtonPathMaps,
base::size(kMicrosoftMotionControllerButtonPathMaps),
kMicrosoftMotionControllerAxisPathMaps,
base::size(kMicrosoftMotionControllerAxisPathMaps)};
constexpr OpenXrControllerInteractionProfile kKHRSimpleInteractionProfile = {
OpenXrInteractionProfileType::kKHRSimple,
"/interaction_profiles/khr/simple_controller",
GamepadMapping::kNone,
kGenericButtonInputProfiles,
base::size(kGenericButtonInputProfiles),
kKronosSimpleControllerButtonPathMaps,
base::size(kKronosSimpleControllerButtonPathMaps),
kKronosSimpleControllerButtonPathMaps,
base::size(kKronosSimpleControllerButtonPathMaps),
nullptr,
0};
constexpr OpenXrControllerInteractionProfile kOculusTouchInteractionProfile = {
OpenXrInteractionProfileType::kOculusTouch,
"/interaction_profiles/oculus/touch_controller",
GamepadMapping::kXrStandard,
kOculusTouchInputProfiles,
base::size(kOculusTouchInputProfiles),
kOculusTouchLeftControllerButtonPathMaps,
base::size(kOculusTouchLeftControllerButtonPathMaps),
kOculusTouchRightControllerButtonPathMaps,
base::size(kOculusTouchRightControllerButtonPathMaps),
kOculusTouchControllerAxisPathMaps,
base::size(kOculusTouchControllerAxisPathMaps)};
constexpr OpenXrControllerInteractionProfile
kOpenXrControllerInteractionProfiles[] = {
kMicrosoftMotionInteractionProfile, kKHRSimpleInteractionProfile,
kOculusTouchInteractionProfile};
} // namespace device
#endif // DEVICE_VR_OPENXR_OPENXR_INTERACTION_PROFILES_H_
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/logging.h"
#include "base/stl_util.h"
#include "device/vr/openxr/openxr_path_helper.h"
#include "device/vr/openxr/openxr_util.h"
......@@ -17,39 +18,48 @@ XrResult OpenXRPathHelper::Initialize(XrInstance instance) {
DCHECK(!initialized_);
// Create path declarations
RETURN_IF_XR_FAILED(xrStringToPath(
instance, "/interaction_profiles/microsoft/motion_controller",
&declared_paths_.microsoft_motion_controller_interaction_profile));
RETURN_IF_XR_FAILED(xrStringToPath(
instance, "/interaction_profiles/khr/simple_controller",
&declared_paths_.khronos_simple_controller_interaction_profile));
for (const auto& profile : kOpenXrControllerInteractionProfiles) {
RETURN_IF_XR_FAILED(
xrStringToPath(instance, profile.path,
&(declared_interaction_profile_paths_[profile.type])));
}
initialized_ = true;
return XR_SUCCESS;
}
std::vector<std::string> OpenXRPathHelper::GetInputProfiles(
OpenXrInteractionProfileType OpenXRPathHelper::GetInputProfileType(
XrPath interaction_profile) const {
DCHECK(initialized_);
if (interaction_profile ==
declared_paths_.microsoft_motion_controller_interaction_profile) {
return {"windows-mixed-reality",
"generic-trigger-squeeze-touchpad-thumbstick"};
for (auto it : declared_interaction_profile_paths_) {
if (it.second == interaction_profile) {
return it.first;
}
}
if (interaction_profile ==
declared_paths_.khronos_simple_controller_interaction_profile) {
return {"generic-button"};
return OpenXrInteractionProfileType::kCount;
}
std::vector<std::string> OpenXRPathHelper::GetInputProfiles(
OpenXrInteractionProfileType interaction_profile) const {
DCHECK(initialized_);
for (auto& it : kOpenXrControllerInteractionProfiles) {
if (it.type == interaction_profile) {
const char* const* const input_profiles = it.input_profiles;
return std::vector<std::string>(input_profiles,
input_profiles + it.profile_size);
}
}
return {};
}
const OpenXRPathHelper::DeclaredPaths& OpenXRPathHelper::GetDeclaredPaths()
const {
DCHECK(initialized_);
return declared_paths_;
XrPath OpenXRPathHelper::GetInteractionProfileXrPath(
OpenXrInteractionProfileType type) const {
if (type == OpenXrInteractionProfileType::kCount) {
return XR_NULL_PATH;
}
return declared_interaction_profile_paths_.at(type);
}
} // namespace device
......@@ -8,30 +8,31 @@
#include <string>
#include <vector>
#include "device/vr/openxr/openxr_interaction_profiles.h"
#include "third_party/openxr/src/include/openxr/openxr.h"
namespace device {
class OpenXRPathHelper {
public:
struct DeclaredPaths {
XrPath microsoft_motion_controller_interaction_profile;
XrPath khronos_simple_controller_interaction_profile;
};
OpenXRPathHelper();
~OpenXRPathHelper();
XrResult Initialize(XrInstance instance);
std::vector<std::string> GetInputProfiles(XrPath interaction_profile) const;
std::vector<std::string> GetInputProfiles(
OpenXrInteractionProfileType interaction_profile) const;
OpenXrInteractionProfileType GetInputProfileType(
XrPath interaction_profile) const;
const DeclaredPaths& GetDeclaredPaths() const;
XrPath GetInteractionProfileXrPath(OpenXrInteractionProfileType type) const;
private:
bool initialized_{false};
DeclaredPaths declared_paths_;
std::unordered_map<OpenXrInteractionProfileType, XrPath>
declared_interaction_profile_paths_;
};
} // namespace device
......
......@@ -786,7 +786,11 @@ XrResult xrSuggestInteractionProfileBindings(
interaction_profile::kMicrosoftMotionControllerInteractionProfile) !=
0 &&
interaction_profile.compare(
interaction_profile::kKHRSimpleControllerInteractionProfile) != 0,
interaction_profile::kKHRSimpleControllerInteractionProfile) !=
0 &&
interaction_profile.compare(
interaction_profile::kOculusTouchControllerInteractionProfile) !=
0,
XR_ERROR_VALIDATION_FAILURE,
"xrSetInteractionProfileSuggestedBindings invalid interaction_profile");
RETURN_IF(suggested_bindings->suggestedBindings == nullptr,
......
......@@ -347,11 +347,12 @@ XrResult OpenXrTestHelper::CreateActionSpace(
XrPath OpenXrTestHelper::GetPath(std::string path_string) {
for (auto it = paths_.begin(); it != paths_.end(); it++) {
if (it->compare(path_string) == 0) {
return it - paths_.begin();
return it - paths_.begin() + 1;
}
}
paths_.emplace_back(path_string);
return paths_.size() - 1;
// path can't be 0 since 0 is reserved for XR_NULL_HANDLE
return paths_.size();
}
XrPath OpenXrTestHelper::GetCurrentInteractionProfile() {
......@@ -763,7 +764,7 @@ void OpenXrTestHelper::LocateSpace(XrSpace space, XrPosef* pose) {
}
std::string OpenXrTestHelper::PathToString(XrPath path) const {
return paths_[path];
return paths_[path - 1];
}
bool OpenXrTestHelper::UpdateData() {
......@@ -927,7 +928,7 @@ XrResult OpenXrTestHelper::ValidateSpace(XrSpace space) const {
}
XrResult OpenXrTestHelper::ValidatePath(XrPath path) const {
RETURN_IF(path >= paths_.size(), XR_ERROR_PATH_INVALID, "XrPath invalid");
RETURN_IF(path > paths_.size(), XR_ERROR_PATH_INVALID, "XrPath invalid");
return XR_SUCCESS;
}
......
......@@ -31,6 +31,9 @@ constexpr char kMicrosoftMotionControllerInteractionProfile[] =
constexpr char kKHRSimpleControllerInteractionProfile[] =
"/interaction_profiles/khr/simple_controller";
constexpr char kOculusTouchControllerInteractionProfile[] =
"/interaction_profiles/oculus/touch_controller";
} // namespace interaction_profile
class OpenXrTestHelper : public device::ServiceTestHook {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment