Skip to content

Commit

Permalink
Clean up OvrSession lifetime for Oculus device.
Browse files Browse the repository at this point in the history
For querying basic hardware information, or supporting magic window,
we shouldn't initialize the Oculus runtime for presenting.  We were
using the Oculus APIs on multiple threads in a way that isn't thread
safe.  The multithreaded usage of ovrSessions also prevented correctly
handling errors like device-lost.

This change makes it so we have different OvrSessions for presenting or
non-presenting, and we only have one of these sessions initialized at a time.
The gamepad data now comes from the OculusRenderLoop, so we aren't using the
Oculus API on 3 separate threads.

We aren't passing the sessions around between threads, so this also makes it more
clear that we are using the API in a threadsafe way.

BUG=852456, 838433, 793364

Change-Id: I4f21ce4d59c081f0e1730b52cc12d1819369a436
Reviewed-on: https://chromium-review.googlesource.com/1116241
Commit-Queue: Bill Orr <billorr@chromium.org>
Reviewed-by: Klaus Weidner <klausw@chromium.org>
Cr-Commit-Position: refs/heads/master@{#573093}
  • Loading branch information
Bill Orr authored and Commit Bot committed Jul 6, 2018
1 parent 0ee1432 commit 582b854
Show file tree
Hide file tree
Showing 10 changed files with 297 additions and 77 deletions.
83 changes: 79 additions & 4 deletions device/vr/oculus/oculus_device.cc
Original file line number Diff line number Diff line change
Expand Up @@ -83,33 +83,51 @@ mojom::VRDisplayInfoPtr CreateVRDisplayInfo(unsigned int id,

} // namespace

OculusDevice::OculusDevice(ovrSession session, ovrGraphicsLuid luid)
OculusDevice::OculusDevice()
: VRDeviceBase(VRDeviceId::OCULUS_DEVICE_ID),
session_(session),
main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
exclusive_controller_binding_(this),
weak_ptr_factory_(this) {
StartOvrSession();
if (!session_) {
return;
}

SetVRDisplayInfo(CreateVRDisplayInfo(GetId(), session_));

render_loop_ = std::make_unique<OculusRenderLoop>(session_, luid);
render_loop_ = std::make_unique<OculusRenderLoop>(
base::BindRepeating(&OculusDevice::OnPresentationEnded,
weak_ptr_factory_.GetWeakPtr()),
base::BindRepeating(&OculusDevice::OnControllerUpdated,
weak_ptr_factory_.GetWeakPtr()));
}

OculusDevice::~OculusDevice() {}
OculusDevice::~OculusDevice() {
StopOvrSession();

device::GamepadDataFetcherManager::GetInstance()->RemoveSourceFactory(
device::GAMEPAD_SOURCE_OCULUS);
data_fetcher_ = nullptr;
}

void OculusDevice::RequestSession(
mojom::XRDeviceRuntimeSessionOptionsPtr options,
mojom::XRRuntime::RequestSessionCallback callback) {
StopOvrSession();

if (!render_loop_->IsRunning())
render_loop_->Start();

if (!render_loop_->IsRunning()) {
std::move(callback).Run(nullptr, nullptr);
StartOvrSession();
return;
}

auto on_request_present_result =
base::BindOnce(&OculusDevice::OnRequestSessionResult,
weak_ptr_factory_.GetWeakPtr(), std::move(callback));

render_loop_->task_runner()->PostTask(
FROM_HERE, base::BindOnce(&OculusRenderLoop::RequestSession,
render_loop_->GetWeakPtr(), std::move(options),
Expand All @@ -124,6 +142,9 @@ void OculusDevice::OnRequestSessionResult(
mojom::VRDisplayFrameTransportOptionsPtr transport_options) {
if (!result) {
std::move(callback).Run(nullptr, nullptr);

// Start magic window again.
StartOvrSession();
return;
}

Expand All @@ -144,6 +165,23 @@ void OculusDevice::OnRequestSessionResult(
base::Unretained(this)));

std::move(callback).Run(std::move(connection), std::move(session_controller));

if (!oculus_gamepad_factory_) {
oculus_gamepad_factory_ =
new OculusGamepadDataFetcher::Factory(GetId(), this);
GamepadDataFetcherManager::GetInstance()->AddFactory(
oculus_gamepad_factory_);
}
}

void OculusDevice::OnControllerUpdated(ovrInputState input,
ovrInputState remote,
ovrTrackingState tracking,
bool has_touch,
bool has_remote) {
if (data_fetcher_)
data_fetcher_->UpdateGamepadData(
{input, remote, tracking, has_touch, has_remote});
}

// XRSessionController
Expand All @@ -160,13 +198,50 @@ void OculusDevice::OnPresentingControllerMojoConnectionError() {
exclusive_controller_binding_.Close();
}

void OculusDevice::OnPresentationEnded() {
StartOvrSession();
}

void OculusDevice::StartOvrSession() {
ovrInitParams initParams = {ovrInit_RequestVersion | ovrInit_Invisible,
OVR_MINOR_VERSION, NULL, 0, 0};
ovrResult result = ovr_Initialize(&initParams);
if (OVR_FAILURE(result)) {
return;
}

ovrGraphicsLuid luid;
result = ovr_Create(&session_, &luid);
if (OVR_FAILURE(result)) {
return;
}
}

void OculusDevice::StopOvrSession() {
if (session_) {
// Shut down our current session so the presentation session can begin.
ovr_Destroy(session_);
session_ = nullptr;
ovr_Shutdown();
}
}

void OculusDevice::OnMagicWindowFrameDataRequest(
mojom::VRMagicWindowProvider::GetFrameDataCallback callback) {
if (!session_) {
std::move(callback).Run(nullptr);
return;
}

ovrTrackingState state = ovr_GetTrackingState(session_, 0, false);

mojom::XRFrameDataPtr frame_data = mojom::XRFrameData::New();
frame_data->pose = mojo::ConvertTo<mojom::VRPosePtr>(state.HeadPose.ThePose);
std::move(callback).Run(std::move(frame_data));
}

void OculusDevice::RegisterDataFetcher(OculusGamepadDataFetcher* data_fetcher) {
data_fetcher_ = data_fetcher;
}

} // namespace device
26 changes: 23 additions & 3 deletions device/vr/oculus/oculus_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "base/macros.h"
#include "base/single_thread_task_runner.h"
#include "device/vr/oculus/oculus_gamepad_data_fetcher.h"
#include "device/vr/public/mojom/vr_service.mojom.h"
#include "device/vr/vr_device_base.h"
#include "mojo/public/cpp/bindings/binding.h"
Expand All @@ -18,9 +19,11 @@ namespace device {

class OculusRenderLoop;

class OculusDevice : public VRDeviceBase, public mojom::XRSessionController {
class OculusDevice : public VRDeviceBase,
public mojom::XRSessionController,
public OculusGamepadDataProvider {
public:
explicit OculusDevice(ovrSession session, ovrGraphicsLuid luid);
explicit OculusDevice();
~OculusDevice() override;

// VRDeviceBase
Expand All @@ -36,15 +39,32 @@ class OculusDevice : public VRDeviceBase, public mojom::XRSessionController {
mojom::VRPresentationProviderPtrInfo provider_info,
mojom::VRDisplayFrameTransportOptionsPtr transport_options);

bool IsInitialized() { return !!session_; }

private:
// XRSessionController
void SetFrameDataRestricted(bool restricted) override;

void OnPresentingControllerMojoConnectionError();

// OculusGamepadDataProvider
void RegisterDataFetcher(OculusGamepadDataFetcher*) override;

void OnPresentationEnded();
void StartOvrSession();
void StopOvrSession();

void OnControllerUpdated(ovrInputState input,
ovrInputState remote,
ovrTrackingState tracking,
bool has_touch,
bool has_remote);

std::unique_ptr<OculusRenderLoop> render_loop_;
OculusGamepadDataFetcher* data_fetcher_ = nullptr;
mojom::VRDisplayInfoPtr display_info_;
ovrSession session_;
ovrSession session_ = nullptr;
OculusGamepadDataFetcher::Factory* oculus_gamepad_factory_ = nullptr;
scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;

mojo::Binding<mojom::XRSessionController> exclusive_controller_binding_;
Expand Down
25 changes: 4 additions & 21 deletions device/vr/oculus/oculus_device_provider.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,6 @@ namespace device {
OculusVRDeviceProvider::OculusVRDeviceProvider() : initialized_(false) {}

OculusVRDeviceProvider::~OculusVRDeviceProvider() {
device::GamepadDataFetcherManager::GetInstance()->RemoveSourceFactory(
device::GAMEPAD_SOURCE_OCULUS);

if (session_)
ovr_Destroy(session_);
ovr_Shutdown();
}

void OculusVRDeviceProvider::Initialize(
Expand All @@ -38,23 +32,12 @@ void OculusVRDeviceProvider::Initialize(

void OculusVRDeviceProvider::CreateDevice() {
// TODO(billorr): Check for headset presence without starting runtime.
ovrInitParams initParams = {ovrInit_RequestVersion, OVR_MINOR_VERSION, NULL,
0, 0};
ovrResult result = ovr_Initialize(&initParams);
if (OVR_FAILURE(result)) {
return;
}
device_ = std::make_unique<OculusDevice>();

// TODO(792657): luid should be used to handle multi-gpu machines.
ovrGraphicsLuid luid;
result = ovr_Create(&session_, &luid);
if (OVR_FAILURE(result)) {
return;
// If the device failed to inialize, don't return it.
if (!device_->IsInitialized()) {
device_ = nullptr;
}

device_ = std::make_unique<OculusDevice>(session_, luid);
GamepadDataFetcherManager::GetInstance()->AddFactory(
new OculusGamepadDataFetcher::Factory(device_->GetId(), session_));
}

bool OculusVRDeviceProvider::Initialized() {
Expand Down
1 change: 0 additions & 1 deletion device/vr/oculus/oculus_device_provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ class DEVICE_VR_EXPORT OculusVRDeviceProvider : public VRDeviceProvider {
void CreateDevice();

bool initialized_;
ovrSession session_ = nullptr;
std::unique_ptr<OculusDevice> device_;

DISALLOW_COPY_AND_ASSIGN(OculusVRDeviceProvider);
Expand Down
46 changes: 26 additions & 20 deletions device/vr/oculus/oculus_gamepad_data_fetcher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,8 @@ void SetTouchData(PadState* state,
} // namespace

OculusGamepadDataFetcher::Factory::Factory(unsigned int display_id,
ovrSession session)
: display_id_(display_id), session_(session) {
OculusGamepadDataProvider* provider)
: display_id_(display_id), provider_(provider) {
DVLOG(1) << __FUNCTION__ << "=" << this;
}

Expand All @@ -181,17 +181,21 @@ OculusGamepadDataFetcher::Factory::~Factory() {

std::unique_ptr<GamepadDataFetcher>
OculusGamepadDataFetcher::Factory::CreateDataFetcher() {
return std::make_unique<OculusGamepadDataFetcher>(display_id_, session_);
return std::make_unique<OculusGamepadDataFetcher>(display_id_, provider_);
}

GamepadSource OculusGamepadDataFetcher::Factory::source() {
return GAMEPAD_SOURCE_OCULUS;
}

OculusGamepadDataFetcher::OculusGamepadDataFetcher(unsigned int display_id,
ovrSession session)
: display_id_(display_id), session_(session) {
OculusGamepadDataFetcher::OculusGamepadDataFetcher(
unsigned int display_id,
OculusGamepadDataProvider* provider)
: display_id_(display_id), weak_ptr_factory_(this) {
DVLOG(1) << __FUNCTION__ << "=" << this;

// Register for updates.
provider->RegisterDataFetcher(this);
}

OculusGamepadDataFetcher::~OculusGamepadDataFetcher() {
Expand All @@ -205,20 +209,17 @@ GamepadSource OculusGamepadDataFetcher::source() {
void OculusGamepadDataFetcher::OnAddedToProvider() {}

void OculusGamepadDataFetcher::GetGamepadData(bool devices_changed_hint) {
ovrInputState input_state;
if ((OVR_SUCCESS(ovr_GetInputState(session_, ovrControllerType_Touch,
&input_state)))) {
ovrTrackingState tracking_state = ovr_GetTrackingState(session_, 0, false);
base::AutoLock lock(lock_);
if (data_.have_input_touch) {
SetTouchData(GetPadState(ovrControllerType_LTouch),
tracking_state.HandPoses[ovrHand_Left], input_state,
data_.tracking.HandPoses[ovrHand_Left], data_.input_touch,
ovrHand_Left, display_id_);
SetTouchData(GetPadState(ovrControllerType_RTouch),
tracking_state.HandPoses[ovrHand_Right], input_state,
data_.tracking.HandPoses[ovrHand_Right], data_.input_touch,
ovrHand_Right, display_id_);
}

if ((OVR_SUCCESS(ovr_GetInputState(session_, ovrControllerType_Remote,
&input_state)))) {
if (data_.have_input_remote) {
PadState* state = GetPadState(ovrControllerType_Remote);
if (state) {
Gamepad& pad = state->data;
Expand All @@ -232,16 +233,21 @@ void OculusGamepadDataFetcher::GetGamepadData(bool devices_changed_hint) {
pad.timestamp = CurrentTimeInMicroseconds();
pad.axes_length = 0;
pad.buttons_length = 0;
SetGamepadButton(&pad, input_state, ovrButton_Enter);
SetGamepadButton(&pad, input_state, ovrButton_Back);
SetGamepadButton(&pad, input_state, ovrButton_Up);
SetGamepadButton(&pad, input_state, ovrButton_Down);
SetGamepadButton(&pad, input_state, ovrButton_Left);
SetGamepadButton(&pad, input_state, ovrButton_Right);
SetGamepadButton(&pad, data_.input_remote, ovrButton_Enter);
SetGamepadButton(&pad, data_.input_remote, ovrButton_Back);
SetGamepadButton(&pad, data_.input_remote, ovrButton_Up);
SetGamepadButton(&pad, data_.input_remote, ovrButton_Down);
SetGamepadButton(&pad, data_.input_remote, ovrButton_Left);
SetGamepadButton(&pad, data_.input_remote, ovrButton_Right);
}
}
}

void OculusGamepadDataFetcher::UpdateGamepadData(OculusInputData data) {
base::AutoLock lock(lock_);
data_ = data;
}

void OculusGamepadDataFetcher::PauseHint(bool paused) {}

} // namespace device
Loading

0 comments on commit 582b854

Please sign in to comment.