Commit 97cffc5c authored by Kevin Qin's avatar Kevin Qin Committed by Commit Bot

Fixing Flaky OpenXR Input Test By Creating Static Wrapper Class

Currently OpenXR tests are flaky because XrInstance is created and
destroyed multiple times. There is also a performance issue because
every time XrCreateInstance called, it will load dlls. The solution is
create a OpenXrStatic class to host the xr instance and static methods.
And have one copy of OpenXrStatic in render process another in where
static functions getting called.


Bug: 1011871
Change-Id: I69843cebaeee9e4b7f30806f431b4ea93182ebca
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1865727
Commit-Queue: Zheng Qin <zheqi@microsoft.com>
Reviewed-by: default avatarAlexander Cooper <alcooper@chromium.org>
Cr-Commit-Position: refs/heads/master@{#708505}
parent 23787ba1
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#if BUILDFLAG(ENABLE_OPENXR) #if BUILDFLAG(ENABLE_OPENXR)
#include "device/vr/openxr/openxr_device.h" #include "device/vr/openxr/openxr_device.h"
#include "device/vr/openxr/openxr_statics.h"
#endif #endif
enum class IsolatedXRRuntimeProvider::RuntimeStatus { enum class IsolatedXRRuntimeProvider::RuntimeStatus {
...@@ -158,7 +159,8 @@ void IsolatedXRRuntimeProvider::SetupPollingForDeviceChanges() { ...@@ -158,7 +159,8 @@ void IsolatedXRRuntimeProvider::SetupPollingForDeviceChanges() {
#if BUILDFLAG(ENABLE_OPENXR) #if BUILDFLAG(ENABLE_OPENXR)
if (base::FeatureList::IsEnabled(features::kOpenXR)) { if (base::FeatureList::IsEnabled(features::kOpenXR)) {
should_check_openxr_ = device::OpenXrDevice::IsApiAvailable(); openxr_statics_ = std::make_unique<device::OpenXrStatics>();
should_check_openxr_ = openxr_statics_->IsApiAvailable();
any_runtimes_available |= should_check_openxr_; any_runtimes_available |= should_check_openxr_;
} }
#endif #endif
...@@ -214,7 +216,7 @@ void IsolatedXRRuntimeProvider::SetWMRRuntimeStatus(RuntimeStatus status) { ...@@ -214,7 +216,7 @@ void IsolatedXRRuntimeProvider::SetWMRRuntimeStatus(RuntimeStatus status) {
#if BUILDFLAG(ENABLE_OPENXR) #if BUILDFLAG(ENABLE_OPENXR)
bool IsolatedXRRuntimeProvider::IsOpenXrHardwareAvailable() { bool IsolatedXRRuntimeProvider::IsOpenXrHardwareAvailable() {
return should_check_openxr_ && device::OpenXrDevice::IsHardwareAvailable(); return should_check_openxr_ && openxr_statics_->IsHardwareAvailable();
} }
void IsolatedXRRuntimeProvider::SetOpenXrRuntimeStatus(RuntimeStatus status) { void IsolatedXRRuntimeProvider::SetOpenXrRuntimeStatus(RuntimeStatus status) {
......
...@@ -18,6 +18,7 @@ class OpenVRDevice; ...@@ -18,6 +18,7 @@ class OpenVRDevice;
class MixedRealityDevice; class MixedRealityDevice;
class MixedRealityDeviceStatics; class MixedRealityDeviceStatics;
class OpenXrDevice; class OpenXrDevice;
class OpenXrStatics;
} // namespace device } // namespace device
class IsolatedXRRuntimeProvider class IsolatedXRRuntimeProvider
...@@ -63,6 +64,7 @@ class IsolatedXRRuntimeProvider ...@@ -63,6 +64,7 @@ class IsolatedXRRuntimeProvider
void SetOpenXrRuntimeStatus(RuntimeStatus status); void SetOpenXrRuntimeStatus(RuntimeStatus status);
bool should_check_openxr_ = false; bool should_check_openxr_ = false;
std::unique_ptr<device::OpenXrDevice> openxr_device_; std::unique_ptr<device::OpenXrDevice> openxr_device_;
std::unique_ptr<device::OpenXrStatics> openxr_statics_;
#endif #endif
mojo::Remote<device::mojom::IsolatedXRRuntimeProviderClient> client_; mojo::Remote<device::mojom::IsolatedXRRuntimeProviderClient> client_;
......
...@@ -245,6 +245,8 @@ if (enable_vr) { ...@@ -245,6 +245,8 @@ if (enable_vr) {
"openxr/openxr_input_helper.h", "openxr/openxr_input_helper.h",
"openxr/openxr_render_loop.cc", "openxr/openxr_render_loop.cc",
"openxr/openxr_render_loop.h", "openxr/openxr_render_loop.h",
"openxr/openxr_statics.cc",
"openxr/openxr_statics.h",
"openxr/openxr_util.cc", "openxr/openxr_util.cc",
"openxr/openxr_util.h", "openxr/openxr_util.h",
] ]
......
...@@ -29,62 +29,8 @@ constexpr XrViewConfigurationType kSupportedViewConfiguration = ...@@ -29,62 +29,8 @@ constexpr XrViewConfigurationType kSupportedViewConfiguration =
XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO; XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
constexpr uint32_t kNumViews = 2; constexpr uint32_t kNumViews = 2;
XrResult CreateInstance(XrInstance* instance) {
XrInstanceCreateInfo instance_create_info = {XR_TYPE_INSTANCE_CREATE_INFO};
strcpy_s(instance_create_info.applicationInfo.applicationName, "Chromium");
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.
const char* extensions[] = {
XR_KHR_D3D11_ENABLE_EXTENSION_NAME,
};
instance_create_info.enabledExtensionCount =
sizeof(extensions) / sizeof(extensions[0]);
instance_create_info.enabledExtensionNames = extensions;
return xrCreateInstance(&instance_create_info, instance);
}
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);
}
} // namespace } // namespace
bool OpenXrApiWrapper::IsHardwareAvailable() {
bool is_available = false;
XrInstance instance = XR_NULL_HANDLE;
XrSystemId system;
if (XR_SUCCEEDED(CreateInstance(&instance)) &&
XR_SUCCEEDED(GetSystem(instance, &system))) {
is_available = true;
}
if (instance != XR_NULL_HANDLE)
xrDestroyInstance(instance);
// System is not allocated so does not need to be destroyed
return is_available;
}
bool OpenXrApiWrapper::IsApiAvailable() {
XrInstance instance;
if (XR_SUCCEEDED(CreateInstance(&instance))) {
xrDestroyInstance(instance);
return true;
}
return false;
}
std::unique_ptr<OpenXrApiWrapper> OpenXrApiWrapper::Create() { std::unique_ptr<OpenXrApiWrapper> OpenXrApiWrapper::Create() {
std::unique_ptr<OpenXrApiWrapper> openxr = std::unique_ptr<OpenXrApiWrapper> openxr =
std::make_unique<OpenXrApiWrapper>(); std::make_unique<OpenXrApiWrapper>();
......
...@@ -38,9 +38,6 @@ class OpenXrApiWrapper { ...@@ -38,9 +38,6 @@ class OpenXrApiWrapper {
static std::unique_ptr<OpenXrApiWrapper> Create(); static std::unique_ptr<OpenXrApiWrapper> Create();
static bool IsHardwareAvailable();
static bool IsApiAvailable();
static VRTestHook* GetTestHook(); static VRTestHook* GetTestHook();
bool session_ended() const { return session_ended_; } bool session_ended() const { return session_ended_; }
......
...@@ -76,14 +76,6 @@ mojom::VRDisplayInfoPtr CreateFakeVRDisplayInfo(device::mojom::XRDeviceId id) { ...@@ -76,14 +76,6 @@ mojom::VRDisplayInfoPtr CreateFakeVRDisplayInfo(device::mojom::XRDeviceId id) {
} // namespace } // namespace
bool OpenXrDevice::IsHardwareAvailable() {
return OpenXrApiWrapper::IsHardwareAvailable();
}
bool OpenXrDevice::IsApiAvailable() {
return OpenXrApiWrapper::IsApiAvailable();
}
OpenXrDevice::OpenXrDevice() OpenXrDevice::OpenXrDevice()
: VRDeviceBase(device::mojom::XRDeviceId::OPENXR_DEVICE_ID), : VRDeviceBase(device::mojom::XRDeviceId::OPENXR_DEVICE_ID),
weak_ptr_factory_(this) { weak_ptr_factory_(this) {
......
...@@ -27,9 +27,6 @@ class DEVICE_VR_EXPORT OpenXrDevice ...@@ -27,9 +27,6 @@ class DEVICE_VR_EXPORT OpenXrDevice
OpenXrDevice(); OpenXrDevice();
~OpenXrDevice() override; ~OpenXrDevice() override;
static bool IsHardwareAvailable();
static bool IsApiAvailable();
// VRDeviceBase // VRDeviceBase
void RequestSession( void RequestSession(
mojom::XRRuntimeSessionOptionsPtr options, mojom::XRRuntimeSessionOptionsPtr options,
......
// Copyright 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.
#include "device/vr/openxr/openxr_statics.h"
#include "device/vr/openxr/openxr_util.h"
namespace device {
OpenXrStatics::OpenXrStatics() : instance_(XR_NULL_HANDLE) {}
OpenXrStatics::~OpenXrStatics() {
if (instance_ != XR_NULL_HANDLE) {
xrDestroyInstance(instance_);
instance_ = XR_NULL_HANDLE;
}
}
bool OpenXrStatics::IsHardwareAvailable() {
if (instance_ == XR_NULL_HANDLE && XR_FAILED(CreateInstance(&instance_))) {
return false;
}
XrSystemId system;
return XR_SUCCEEDED(GetSystem(instance_, &system));
}
bool OpenXrStatics::IsApiAvailable() {
return instance_ != XR_NULL_HANDLE ||
XR_SUCCEEDED(CreateInstance(&instance_));
}
} // namespace device
\ No newline at end of file
// Copyright 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_STATICS_H_
#define DEVICE_VR_OPENXR_OPENXR_STATICS_H_
#include <d3d11.h>
#include <memory>
#include "device/vr/vr_export.h"
#include "third_party/openxr/src/include/openxr/openxr.h"
#include "third_party/openxr/src/include/openxr/openxr_platform.h"
namespace device {
class DEVICE_VR_EXPORT OpenXrStatics {
public:
OpenXrStatics();
~OpenXrStatics();
bool IsHardwareAvailable();
bool IsApiAvailable();
private:
XrInstance instance_;
};
} // namespace device
#endif // DEVICE_VR_WINDOWS_MIXED_REALITY_MIXED_REALITY_STATICS_H_
\ No newline at end of file
...@@ -4,6 +4,11 @@ ...@@ -4,6 +4,11 @@
#include "device/vr/openxr/openxr_util.h" #include "device/vr/openxr/openxr_util.h"
#include <d3d11.h>
#include <string>
#include "third_party/openxr/src/include/openxr/openxr_platform.h"
namespace device { namespace device {
XrPosef PoseIdentity() { XrPosef PoseIdentity() {
...@@ -12,4 +17,30 @@ XrPosef PoseIdentity() { ...@@ -12,4 +17,30 @@ XrPosef PoseIdentity() {
return pose; return pose;
} }
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);
}
XrResult CreateInstance(XrInstance* instance) {
XrInstanceCreateInfo instance_create_info = {XR_TYPE_INSTANCE_CREATE_INFO};
strcpy_s(instance_create_info.applicationInfo.applicationName, "Chromium");
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.
const char* extensions[] = {
XR_KHR_D3D11_ENABLE_EXTENSION_NAME,
};
instance_create_info.enabledExtensionCount =
sizeof(extensions) / sizeof(extensions[0]);
instance_create_info.enabledExtensionNames = extensions;
return xrCreateInstance(&instance_create_info, instance);
}
} // namespace device } // namespace device
...@@ -42,6 +42,10 @@ namespace device { ...@@ -42,6 +42,10 @@ namespace device {
// orientation is {0, 0, 0, 1}. // orientation is {0, 0, 0, 1}.
XrPosef PoseIdentity(); XrPosef PoseIdentity();
XrResult GetSystem(XrInstance instance, XrSystemId* system);
XrResult CreateInstance(XrInstance* instance);
} // namespace device } // namespace device
#endif // DEVICE_VR_OPENXR_OPENXR_UTIL_H_ #endif // DEVICE_VR_OPENXR_OPENXR_UTIL_H_
...@@ -146,9 +146,7 @@ XrResult xrCreateInstance(const XrInstanceCreateInfo* create_info, ...@@ -146,9 +146,7 @@ XrResult xrCreateInstance(const XrInstanceCreateInfo* create_info,
"enabledExtensionNames contains invalid extensions"); "enabledExtensionNames contains invalid extensions");
} }
// Return the test helper object back to the OpenXrAPIWrapper so it can use *instance = g_test_helper.CreateInstance();
// it as the TestHookRegistration.
*instance = reinterpret_cast<XrInstance>(&g_test_helper);
return XR_SUCCESS; return XR_SUCCESS;
} }
...@@ -250,7 +248,7 @@ XrResult xrDestroyInstance(XrInstance instance) { ...@@ -250,7 +248,7 @@ XrResult xrDestroyInstance(XrInstance instance) {
XrResult xr_result; XrResult xr_result;
RETURN_IF_XR_FAILED(g_test_helper.ValidateInstance(instance)); RETURN_IF_XR_FAILED(g_test_helper.ValidateInstance(instance));
g_test_helper.Reset();
return XR_SUCCESS; return XR_SUCCESS;
} }
......
...@@ -48,7 +48,11 @@ uint32_t OpenXrTestHelper::NumViews() { ...@@ -48,7 +48,11 @@ uint32_t OpenXrTestHelper::NumViews() {
} }
OpenXrTestHelper::OpenXrTestHelper() OpenXrTestHelper::OpenXrTestHelper()
: system_id_(0), // since openxr_statics is created first, so the first instance returned
// should be a fake one since openxr_statics does not need to use
// test_hook_;
: create_fake_instance_(true),
system_id_(0),
session_(XR_NULL_HANDLE), session_(XR_NULL_HANDLE),
session_state_(XR_SESSION_STATE_UNKNOWN), session_state_(XR_SESSION_STATE_UNKNOWN),
swapchain_(XR_NULL_HANDLE), swapchain_(XR_NULL_HANDLE),
...@@ -58,6 +62,39 @@ OpenXrTestHelper::OpenXrTestHelper() ...@@ -58,6 +62,39 @@ OpenXrTestHelper::OpenXrTestHelper()
OpenXrTestHelper::~OpenXrTestHelper() = default; OpenXrTestHelper::~OpenXrTestHelper() = default;
void OpenXrTestHelper::Reset() {
session_ = XR_NULL_HANDLE;
session_state_ = XR_SESSION_STATE_UNKNOWN;
swapchain_ = XR_NULL_HANDLE;
create_fake_instance_ = true;
system_id_ = 0;
d3d_device_ = nullptr;
acquired_swapchain_texture_ = 0;
next_action_space_ = 0;
next_predicted_display_time_ = 0;
// vectors
textures_arr_.clear();
paths_.clear();
// unordered_maps
actions_.clear();
action_spaces_.clear();
reference_spaces_.clear();
action_sets_.clear();
float_action_states_.clear();
boolean_action_states_.clear();
v2f_action_states_.clear();
pose_action_state_.clear();
// unordered_sets
action_names_.clear();
action_localized_names_.clear();
action_set_names_.clear();
action_set_localized_names_.clear();
}
void OpenXrTestHelper::TestFailure() { void OpenXrTestHelper::TestFailure() {
NOTREACHED(); NOTREACHED();
} }
...@@ -125,6 +162,20 @@ XrSwapchain OpenXrTestHelper::GetSwapchain() { ...@@ -125,6 +162,20 @@ XrSwapchain OpenXrTestHelper::GetSwapchain() {
return swapchain_; return swapchain_;
} }
XrInstance OpenXrTestHelper::CreateInstance() {
// Return the test helper object back to the OpenXrAPIWrapper so it can use
// it as the TestHookRegistration.However we have to return different instance
// for openxr_statics since openxr loader records instance created and
// detroyed. The first instance is used by openxr_statics which does not need
// to use test_hook_, So we can give it an arbitrary instance as long as
// ValidateInstance method remember it's an valid option.
if (create_fake_instance_) {
create_fake_instance_ = false;
return reinterpret_cast<XrInstance>(this + 1);
}
return reinterpret_cast<XrInstance>(this);
}
XrResult OpenXrTestHelper::GetActionStateFloat(XrAction action, XrResult OpenXrTestHelper::GetActionStateFloat(XrAction action,
XrActionStateFloat* data) const { XrActionStateFloat* data) const {
XrResult xr_result; XrResult xr_result;
...@@ -627,7 +678,9 @@ XrResult OpenXrTestHelper::ValidateActionSpaceCreateInfo( ...@@ -627,7 +678,9 @@ XrResult OpenXrTestHelper::ValidateActionSpaceCreateInfo(
XrResult OpenXrTestHelper::ValidateInstance(XrInstance instance) const { XrResult OpenXrTestHelper::ValidateInstance(XrInstance instance) const {
// The Fake OpenXr Runtime returns this global OpenXrTestHelper object as the // The Fake OpenXr Runtime returns this global OpenXrTestHelper object as the
// instance value on xrCreateInstance. // instance value on xrCreateInstance.
RETURN_IF(reinterpret_cast<OpenXrTestHelper*>(instance) != this,
RETURN_IF(reinterpret_cast<OpenXrTestHelper*>(instance) != this &&
reinterpret_cast<OpenXrTestHelper*>(instance) != (this + 1),
XR_ERROR_VALIDATION_FAILURE, "XrInstance invalid"); XR_ERROR_VALIDATION_FAILURE, "XrInstance invalid");
return XR_SUCCESS; return XR_SUCCESS;
......
...@@ -27,7 +27,7 @@ class OpenXrTestHelper : public device::ServiceTestHook { ...@@ -27,7 +27,7 @@ class OpenXrTestHelper : public device::ServiceTestHook {
public: public:
OpenXrTestHelper(); OpenXrTestHelper();
~OpenXrTestHelper(); ~OpenXrTestHelper();
void Reset();
void TestFailure(); void TestFailure();
// TestHookRegistration // TestHookRegistration
...@@ -43,6 +43,7 @@ class OpenXrTestHelper : public device::ServiceTestHook { ...@@ -43,6 +43,7 @@ class OpenXrTestHelper : public device::ServiceTestHook {
XrSystemId GetSystemId(); XrSystemId GetSystemId();
XrSwapchain GetSwapchain(); XrSwapchain GetSwapchain();
XrInstance CreateInstance();
XrResult GetActionStateFloat(XrAction action, XrActionStateFloat* data) const; XrResult GetActionStateFloat(XrAction action, XrActionStateFloat* data) const;
XrResult GetActionStateBoolean(XrAction action, XrResult GetActionStateBoolean(XrAction action,
XrActionStateBoolean* data) const; XrActionStateBoolean* data) const;
...@@ -123,6 +124,8 @@ class OpenXrTestHelper : public device::ServiceTestHook { ...@@ -123,6 +124,8 @@ class OpenXrTestHelper : public device::ServiceTestHook {
device::ControllerFrameData GetControllerDataFromPath( device::ControllerFrameData GetControllerDataFromPath(
std::string path_string) const; std::string path_string) const;
bool create_fake_instance_;
// Properties of the mock OpenXR runtime that doesn't change throughout the // Properties of the mock OpenXR runtime that doesn't change throughout the
// lifetime of the instance. However, these aren't static because they are // lifetime of the instance. However, these aren't static because they are
// initialized to an invalid value and set to their actual value in their // initialized to an invalid value and set to their actual value in their
......
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