blob: fa02637fc8505a7c32410005d9c3831a40705e51 [file]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "device/vr/openxr/openxr_util.h"
#include <string>
#include "base/check_op.h"
#include "base/version.h"
#include "base/win/scoped_handle.h"
#include "build/build_config.h"
#include "components/version_info/version_info.h"
#include "ui/gfx/geometry/angle_conversions.h"
#include "ui/gfx/geometry/quaternion.h"
#include "ui/gfx/geometry/transform.h"
#include "ui/gfx/geometry/transform_util.h"
namespace device {
XrPosef PoseIdentity() {
XrPosef pose{};
pose.orientation.w = 1;
return pose;
}
gfx::Transform XrPoseToGfxTransform(const XrPosef& pose) {
gfx::DecomposedTransform decomp;
decomp.quaternion = gfx::Quaternion(pose.orientation.x, pose.orientation.y,
pose.orientation.z, pose.orientation.w);
decomp.translate[0] = pose.position.x;
decomp.translate[1] = pose.position.y;
decomp.translate[2] = pose.position.z;
return gfx::Transform::Compose(decomp);
}
XrPosef GfxTransformToXrPose(const gfx::Transform& transform) {
absl::optional<gfx::DecomposedTransform> decomposed_transform =
transform.Decompose();
// This pose should always be a simple translation and rotation so this should
// always be true
DCHECK(decomposed_transform);
return {{static_cast<float>(decomposed_transform->quaternion.x()),
static_cast<float>(decomposed_transform->quaternion.y()),
static_cast<float>(decomposed_transform->quaternion.z()),
static_cast<float>(decomposed_transform->quaternion.w())},
{static_cast<float>(decomposed_transform->translate[0]),
static_cast<float>(decomposed_transform->translate[1]),
static_cast<float>(decomposed_transform->translate[2])}};
}
bool IsPoseValid(XrSpaceLocationFlags locationFlags) {
XrSpaceLocationFlags PoseValidFlags = XR_SPACE_LOCATION_POSITION_VALID_BIT |
XR_SPACE_LOCATION_ORIENTATION_VALID_BIT;
return (locationFlags & PoseValidFlags) == PoseValidFlags;
}
XrResult GetSystem(XrInstance instance, XrSystemId* system) {
XrSystemGetInfo system_info = {XR_TYPE_SYSTEM_GET_INFO};
system_info.formFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
return xrGetSystem(instance, &system_info, system);
}
#if BUILDFLAG(IS_WIN)
bool IsRunningInWin32AppContainer() {
base::win::ScopedHandle scopedProcessToken;
HANDLE processToken;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &processToken)) {
return false;
}
scopedProcessToken.Set(processToken);
BOOL isAppContainer;
DWORD dwSize = sizeof(BOOL);
if (!GetTokenInformation(scopedProcessToken.Get(), TokenIsAppContainer,
&isAppContainer, dwSize, &dwSize)) {
return false;
}
return isAppContainer;
}
#else
bool IsRunningInWin32AppContainer() {
return false;
}
#endif
XrResult CreateInstance(
XrInstance* instance,
const OpenXrExtensionEnumeration& extension_enumeration) {
XrInstanceCreateInfo instance_create_info = {XR_TYPE_INSTANCE_CREATE_INFO};
std::string application_name = version_info::GetProductName() + " " +
version_info::GetMajorVersionNumber();
errno_t error =
strcpy_s(instance_create_info.applicationInfo.applicationName,
std::size(instance_create_info.applicationInfo.applicationName),
application_name.c_str());
DCHECK_EQ(error, 0);
base::Version version = version_info::GetVersion();
DCHECK_EQ(version.components().size(), 4uLL);
uint32_t build = version.components()[2];
// application version will be the build number of each vendor
instance_create_info.applicationInfo.applicationVersion = build;
error = strcpy_s(instance_create_info.applicationInfo.engineName,
std::size(instance_create_info.applicationInfo.engineName),
"Chromium");
DCHECK_EQ(error, 0);
// engine version should be the build number of chromium
instance_create_info.applicationInfo.engineVersion = build;
instance_create_info.applicationInfo.apiVersion = XR_CURRENT_API_VERSION;
// xrCreateInstance validates the list of extensions and returns
// XR_ERROR_EXTENSION_NOT_PRESENT if an extension is not supported,
// so we don't need to call xrEnumerateInstanceExtensionProperties
// to validate these extensions.
// Since the OpenXR backend only knows how to draw with D3D11 at the moment,
// the XR_KHR_D3D11_ENABLE_EXTENSION_NAME is required.
std::vector<const char*> extensions{XR_KHR_D3D11_ENABLE_EXTENSION_NAME};
// If we are in an app container, we must require the app container extension
// to ensure robust execution of the OpenXR runtime
if (IsRunningInWin32AppContainer()) {
// Add the win32 app container compatible extension to our list of
// extensions. If this runtime does not support execution in an app
// container environment, one of xrCreateInstance or xrGetSystem will fail.
extensions.push_back(XR_EXT_WIN32_APPCONTAINER_COMPATIBLE_EXTENSION_NAME);
}
auto EnableExtensionIfSupported = [&extension_enumeration,
&extensions](const char* extension) {
if (extension_enumeration.ExtensionSupported(extension)) {
extensions.push_back(extension);
}
};
// XR_MSFT_UNBOUNDED_REFERENCE_SPACE_EXTENSION_NAME, is required for optional
// functionality (unbounded reference spaces) and thus only requested if it is
// available.
EnableExtensionIfSupported(XR_MSFT_UNBOUNDED_REFERENCE_SPACE_EXTENSION_NAME);
// Input extensions. These enable interaction profiles not defined in the core
// spec
EnableExtensionIfSupported(kExtSamsungOdysseyControllerExtensionName);
EnableExtensionIfSupported(kExtHPMixedRealityControllerExtensionName);
EnableExtensionIfSupported(kMSFTHandInteractionExtensionName);
EnableExtensionIfSupported(XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME);
EnableExtensionIfSupported(XR_EXT_HAND_TRACKING_EXTENSION_NAME);
EnableExtensionIfSupported(XR_MSFT_SPATIAL_ANCHOR_EXTENSION_NAME);
EnableExtensionIfSupported(XR_MSFT_SCENE_UNDERSTANDING_EXTENSION_NAME);
EnableExtensionIfSupported(
XR_MSFT_SECONDARY_VIEW_CONFIGURATION_EXTENSION_NAME);
if (extension_enumeration.ExtensionSupported(
XR_MSFT_SECONDARY_VIEW_CONFIGURATION_EXTENSION_NAME)) {
EnableExtensionIfSupported(XR_MSFT_FIRST_PERSON_OBSERVER_EXTENSION_NAME);
}
EnableExtensionIfSupported(
XR_KHR_WIN32_CONVERT_PERFORMANCE_COUNTER_TIME_EXTENSION_NAME);
instance_create_info.enabledExtensionCount =
static_cast<uint32_t>(extensions.size());
instance_create_info.enabledExtensionNames = extensions.data();
return xrCreateInstance(&instance_create_info, instance);
}
std::vector<XrEnvironmentBlendMode> GetSupportedBlendModes(XrInstance instance,
XrSystemId system) {
// Query the list of supported environment blend modes for the current system.
uint32_t blend_mode_count;
const XrViewConfigurationType kSupportedViewConfiguration =
XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
if (XR_FAILED(xrEnumerateEnvironmentBlendModes(instance, system,
kSupportedViewConfiguration, 0,
&blend_mode_count, nullptr)))
return {}; // empty vector
std::vector<XrEnvironmentBlendMode> environment_blend_modes(blend_mode_count);
if (XR_FAILED(xrEnumerateEnvironmentBlendModes(
instance, system, kSupportedViewConfiguration, blend_mode_count,
&blend_mode_count, environment_blend_modes.data())))
return {}; // empty vector
return environment_blend_modes;
}
} // namespace device