Commit 83e4a43b authored by Alex Cooper's avatar Alex Cooper Committed by Commit Bot

Refactor VRPose to fit better with WebXr concepts

This changes pose_reset and input_state attributes that lived on VRPose
to instead live on XRFrameData. This de-couples some frame state from
VRPose and paves the way for it to be used instead of gfx::Transforms
for some entities.

Bug: 1017872
Change-Id: I76474845436168a144f929c8cb94bd4a50b15fe6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1945278Reviewed-by: default avatarWill Harris <wfh@chromium.org>
Reviewed-by: default avatarKlaus Weidner <klausw@chromium.org>
Reviewed-by: default avatarBrandon Jones <bajones@chromium.org>
Commit-Queue: Alexander Cooper <alcooper@chromium.org>
Cr-Commit-Position: refs/heads/master@{#721135}
parent 96e4d92c
...@@ -786,14 +786,14 @@ void ArCoreGl::ProcessFrame( ...@@ -786,14 +786,14 @@ void ArCoreGl::ProcessFrame(
mojom::XRInputSourceStatePtr input_state = GetInputSourceState(); mojom::XRInputSourceStatePtr input_state = GetInputSourceState();
if (input_state) { if (input_state) {
input_states_.push_back(std::move(input_state)); input_states_.push_back(std::move(input_state));
frame_data->pose->input_state = std::move(input_states_); frame_data->input_state = std::move(input_states_);
} }
// Get results for hit test subscriptions. // Get results for hit test subscriptions.
frame_data->hit_test_subscription_results = frame_data->hit_test_subscription_results =
arcore_->GetHitTestSubscriptionResults( arcore_->GetHitTestSubscriptionResults(
mojo::ConvertTo<gfx::Transform>(frame_data->pose), mojo::ConvertTo<gfx::Transform>(frame_data->pose),
frame_data->pose->input_state); frame_data->input_state);
} }
// Get anchors data, including anchors created this frame. // Get anchors data, including anchors created this frame.
......
...@@ -930,11 +930,11 @@ void GvrSchedulerDelegate::SendVSync(device::mojom::VRPosePtr pose, ...@@ -930,11 +930,11 @@ void GvrSchedulerDelegate::SendVSync(device::mojom::VRPosePtr pose,
// Process all events. Check for ones we wish to react to. // Process all events. Check for ones we wish to react to.
gvr::Event last_event; gvr::Event last_event;
while (gvr_api_->PollEvent(&last_event)) { while (gvr_api_->PollEvent(&last_event)) {
pose->pose_reset |= last_event.type == GVR_EVENT_RECENTER; frame_data->mojo_space_reset |= last_event.type == GVR_EVENT_RECENTER;
} }
TRACE_EVENT0("gpu", "GvrSchedulerDelegate::XRInput"); TRACE_EVENT0("gpu", "GvrSchedulerDelegate::XRInput");
pose->input_state = std::move(input_states_); frame_data->input_state = std::move(input_states_);
frame_data->pose = std::move(pose); frame_data->pose = std::move(pose);
......
...@@ -62,13 +62,10 @@ mojom::XRFrameDataPtr OculusRenderLoop::GetNextFrameData() { ...@@ -62,13 +62,10 @@ mojom::XRFrameDataPtr OculusRenderLoop::GetNextFrameData() {
sensor_time_ = ovr_GetTimeInSeconds(); sensor_time_ = ovr_GetTimeInSeconds();
frame_data->time_delta = base::TimeDelta::FromSecondsD(predicted_time); frame_data->time_delta = base::TimeDelta::FromSecondsD(predicted_time);
mojom::VRPosePtr pose = frame_data->pose = mojo::ConvertTo<mojom::VRPosePtr>(state.HeadPose.ThePose);
mojo::ConvertTo<mojom::VRPosePtr>(state.HeadPose.ThePose);
last_render_pose_ = state.HeadPose.ThePose; last_render_pose_ = state.HeadPose.ThePose;
DCHECK(pose); frame_data->input_state = GetInputState(state);
pose->input_state = GetInputState(state);
frame_data->pose = std::move(pose);
return frame_data; return frame_data;
} }
......
...@@ -173,30 +173,24 @@ void OpenVRRenderLoop::OnSessionStart() { ...@@ -173,30 +173,24 @@ void OpenVRRenderLoop::OnSessionStart() {
LogViewerType(type); LogViewerType(type);
} }
mojom::VRPosePtr OpenVRRenderLoop::GetPose() {
vr::TrackedDevicePose_t rendering_poses[vr::k_unMaxTrackedDeviceCount];
TRACE_EVENT0("gpu", "WaitGetPoses");
openvr_->GetCompositor()->WaitGetPoses(
rendering_poses, vr::k_unMaxTrackedDeviceCount, nullptr, 0);
mojom::VRPosePtr pose = mojo::ConvertTo<mojom::VRPosePtr>(
rendering_poses[vr::k_unTrackedDeviceIndex_Hmd]);
// Update WebXR input sources.
DCHECK(pose);
pose->input_state =
GetInputState(rendering_poses, vr::k_unMaxTrackedDeviceCount);
return pose;
}
mojom::XRFrameDataPtr OpenVRRenderLoop::GetNextFrameData() { mojom::XRFrameDataPtr OpenVRRenderLoop::GetNextFrameData() {
mojom::XRFrameDataPtr frame_data = mojom::XRFrameData::New(); mojom::XRFrameDataPtr frame_data = mojom::XRFrameData::New();
frame_data->frame_id = next_frame_id_; frame_data->frame_id = next_frame_id_;
if (openvr_) { if (openvr_) {
frame_data->pose = GetPose(); vr::TrackedDevicePose_t rendering_poses[vr::k_unMaxTrackedDeviceCount];
TRACE_EVENT0("gpu", "WaitGetPoses");
openvr_->GetCompositor()->WaitGetPoses(
rendering_poses, vr::k_unMaxTrackedDeviceCount, nullptr, 0);
frame_data->pose = mojo::ConvertTo<mojom::VRPosePtr>(
rendering_poses[vr::k_unTrackedDeviceIndex_Hmd]);
// Update WebXR input sources.
frame_data->input_state =
GetInputState(rendering_poses, vr::k_unMaxTrackedDeviceCount);
vr::Compositor_FrameTiming timing; vr::Compositor_FrameTiming timing;
timing.m_nSize = sizeof(vr::Compositor_FrameTiming); timing.m_nSize = sizeof(vr::Compositor_FrameTiming);
bool valid_time = openvr_->GetCompositor()->GetFrameTiming(&timing); bool valid_time = openvr_->GetCompositor()->GetFrameTiming(&timing);
......
...@@ -43,7 +43,6 @@ class OpenVRRenderLoop : public XRCompositorCommon { ...@@ -43,7 +43,6 @@ class OpenVRRenderLoop : public XRCompositorCommon {
bool SubmitCompositedFrame() override; bool SubmitCompositedFrame() override;
// Helpers to implement XRDeviceAbstraction. // Helpers to implement XRDeviceAbstraction.
mojom::VRPosePtr GetPose();
std::vector<mojom::XRInputSourceStatePtr> GetInputState( std::vector<mojom::XRInputSourceStatePtr> GetInputState(
vr::TrackedDevicePose_t* poses, vr::TrackedDevicePose_t* poses,
uint32_t count); uint32_t count);
......
...@@ -38,10 +38,11 @@ mojom::XRFrameDataPtr OpenXrRenderLoop::GetNextFrameData() { ...@@ -38,10 +38,11 @@ mojom::XRFrameDataPtr OpenXrRenderLoop::GetNextFrameData() {
frame_data->time_delta = frame_data->time_delta =
base::TimeDelta::FromNanoseconds(openxr_->GetPredictedDisplayTime()); base::TimeDelta::FromNanoseconds(openxr_->GetPredictedDisplayTime());
frame_data->pose = mojom::VRPose::New(); frame_data->input_state =
frame_data->pose->input_state =
input_helper_->GetInputState(openxr_->GetPredictedDisplayTime()); input_helper_->GetInputState(openxr_->GetPredictedDisplayTime());
frame_data->pose = mojom::VRPose::New();
base::Optional<gfx::Quaternion> orientation; base::Optional<gfx::Quaternion> orientation;
base::Optional<gfx::Point3F> position; base::Optional<gfx::Point3F> position;
if (XR_SUCCEEDED(openxr_->GetHeadPose( if (XR_SUCCEEDED(openxr_->GetHeadPose(
......
...@@ -188,8 +188,9 @@ struct VRFieldOfView { ...@@ -188,8 +188,9 @@ struct VRFieldOfView {
float right_degrees; float right_degrees;
}; };
// A display's position, orientation, velocity, and acceleration state at the // An entity's pose. Used by entities for which either position or orientation
// given timestamp. // may sometimes not be known. Also supports those poses where the position may
// be emulated and this is worth telling consumers.
struct VRPose { struct VRPose {
gfx.mojom.Quaternion? orientation; gfx.mojom.Quaternion? orientation;
gfx.mojom.Point3F? position; gfx.mojom.Point3F? position;
...@@ -197,15 +198,6 @@ struct VRPose { ...@@ -197,15 +198,6 @@ struct VRPose {
// True when position is estimated by something like a neck or arm model. // True when position is estimated by something like a neck or arm model.
// False when position is based on sensors tracking a 6DoF pose. // False when position is based on sensors tracking a 6DoF pose.
bool emulated_position; bool emulated_position;
// For WebXR sessions only, reports the state of all active input devices
// synced with the head pose.
array<XRInputSourceState>? input_state;
// Indicates that a reset pose event was triggered, either by device specific
// UI or by some other method, and handled on the browser side, and the
// renderer should now bubble up an event to the WebXR Device API.
bool pose_reset;
}; };
// An entity's pose. Used by entities for which both position and orientation is // An entity's pose. Used by entities for which both position and orientation is
...@@ -426,6 +418,16 @@ struct XRFrameData { ...@@ -426,6 +418,16 @@ struct XRFrameData {
// for rendering. // for rendering.
gpu.mojom.MailboxHolder? buffer_holder; gpu.mojom.MailboxHolder? buffer_holder;
// Indicates that there has been a significant discontinuity in the mojo space
// coordinate system, and that poses from this point forward with the same
// coordinates as those received previously may not actually be in the same
// position. This could have been triggered either via device specific UI or
// due to a major change in tracking locatibility, but should not typically
// be used when recovering from tracking loss.
// This event should be bubbled up as a reference space reset event:
// https://immersive-web.github.io/webxr/#eventdef-xrreferencespace-reset
bool mojo_space_reset;
// Exclusive session values // Exclusive session values
// The frame_id maps frame data to a frame arriving from the compositor. IDs // The frame_id maps frame data to a frame arriving from the compositor. IDs
...@@ -445,6 +447,13 @@ struct XRFrameData { ...@@ -445,6 +447,13 @@ struct XRFrameData {
VREyeParameters? left_eye; VREyeParameters? left_eye;
VREyeParameters? right_eye; VREyeParameters? right_eye;
// For immersive sessions only, reports the state of all active input devices
// at the time of this frame. If a session has indicated that it
// |uses_input_eventing|, then these input states should not fire select,
// squeeze, or similar events, but all controller state, including current
// button states, should still be updated.
array<XRInputSourceState>? input_state;
// Stage parameters may be provided per-frame, or only re-computed // Stage parameters may be provided per-frame, or only re-computed
// periodically. However, setting the stage parameters to null is perfectly // periodically. However, setting the stage parameters to null is perfectly
// valid in some cases (e.g. we've lost tracking), so we can't just use // valid in some cases (e.g. we've lost tracking), so we can't just use
......
...@@ -873,7 +873,7 @@ mojom::XRFrameDataPtr MixedRealityRenderLoop::GetNextFrameData() { ...@@ -873,7 +873,7 @@ mojom::XRFrameDataPtr MixedRealityRenderLoop::GetNextFrameData() {
current_display_info_.Clone())); current_display_info_.Clone()));
} }
ret->pose->input_state = ret->input_state =
input_helper_->GetInputState(anchor_origin_.get(), timestamp_.get()); input_helper_->GetInputState(anchor_origin_.get(), timestamp_.get());
ret->pose->emulated_position = emulated_position_; ret->pose->emulated_position = emulated_position_;
......
...@@ -397,12 +397,12 @@ void XRFrameProvider::ProcessScheduledFrame( ...@@ -397,12 +397,12 @@ void XRFrameProvider::ProcessScheduledFrame(
if (!immersive_session_ || immersive_session_->ended()) if (!immersive_session_ || immersive_session_->ended())
return; return;
if (frame_pose && frame_pose->pose_reset) { if (frame_data && frame_data->mojo_space_reset) {
immersive_session_->OnPoseReset(); immersive_session_->OnMojoSpaceReset();
} }
// Check if immersive session is still set as OnPoseReset may have allowed a // Check if immersive session is still set as |OnMojoSpaceReset| may have
// ForceEndSession to be triggered. // allowed a ForceEndSession to be triggered.
if (!immersive_session_ || immersive_session_->ended()) { if (!immersive_session_ || immersive_session_->ended()) {
return; return;
} }
...@@ -457,8 +457,8 @@ void XRFrameProvider::ProcessScheduledFrame( ...@@ -457,8 +457,8 @@ void XRFrameProvider::ProcessScheduledFrame(
if (session->ended()) if (session->ended())
continue; continue;
if (frame_pose && frame_pose->pose_reset) { if (frame_data && frame_data->mojo_space_reset) {
session->OnPoseReset(); session->OnMojoSpaceReset();
} }
// If the pose reset caused us to end, we should stop processing. // If the pose reset caused us to end, we should stop processing.
......
...@@ -1398,10 +1398,10 @@ void XRSession::UpdatePresentationFrameState( ...@@ -1398,10 +1398,10 @@ void XRSession::UpdatePresentationFrameState(
emulated_position_ = emulated_position; emulated_position_ = emulated_position;
// Process XR input sources // Process XR input sources
if (frame_pose) { if (frame_data) {
base::span<const device::mojom::blink::XRInputSourceStatePtr> input_states; base::span<const device::mojom::blink::XRInputSourceStatePtr> input_states;
if (frame_pose->input_state.has_value()) if (frame_data->input_state.has_value())
input_states = frame_pose->input_state.value(); input_states = frame_data->input_state.value();
OnInputStateChangeInternal(frame_id, input_states); OnInputStateChangeInternal(frame_id, input_states);
...@@ -1689,7 +1689,7 @@ void XRSession::RemoveTransientInputSource(XRInputSource* input_source) { ...@@ -1689,7 +1689,7 @@ void XRSession::RemoveTransientInputSource(XRInputSource* input_source) {
event_type_names::kInputsourceschange, this, {}, {input_source})); event_type_names::kInputsourceschange, this, {}, {input_source}));
} }
void XRSession::OnPoseReset() { void XRSession::OnMojoSpaceReset() {
for (const auto& reference_space : reference_spaces_) { for (const auto& reference_space : reference_spaces_) {
reference_space->OnReset(); reference_space->OnReset();
} }
......
...@@ -203,7 +203,7 @@ class XRSession final ...@@ -203,7 +203,7 @@ class XRSession final
void AddTransientInputSource(XRInputSource* input_source); void AddTransientInputSource(XRInputSource* input_source);
void RemoveTransientInputSource(XRInputSource* input_source); void RemoveTransientInputSource(XRInputSource* input_source);
void OnPoseReset(); void OnMojoSpaceReset();
const device::mojom::blink::VRDisplayInfoPtr& GetVRDisplayInfo() const { const device::mojom::blink::VRDisplayInfoPtr& GetVRDisplayInfo() const {
return display_info_; return display_info_;
......
...@@ -216,7 +216,7 @@ class MockRuntime { ...@@ -216,7 +216,7 @@ class MockRuntime {
this.pose_ = null; this.pose_ = null;
this.next_frame_id_ = 0; this.next_frame_id_ = 0;
this.bounds_ = null; this.bounds_ = null;
this.send_pose_reset_ = false; this.send_mojo_space_reset_ = false;
this.service_ = service; this.service_ = service;
...@@ -370,7 +370,7 @@ class MockRuntime { ...@@ -370,7 +370,7 @@ class MockRuntime {
} }
simulateResetPose() { simulateResetPose() {
this.send_pose_reset_ = true; this.send_mojo_space_reset_ = true;
} }
simulateInputSourceConnection(fakeInputSourceInit) { simulateInputSourceConnection(fakeInputSourceInit) {
...@@ -514,22 +514,22 @@ class MockRuntime { ...@@ -514,22 +514,22 @@ class MockRuntime {
// XRFrameDataProvider implementation. // XRFrameDataProvider implementation.
getFrameData() { getFrameData() {
let mojo_space_reset = this.send_mojo_space_reset_;
this.send_mojo_space_reset_ = false;
if (this.pose_) { if (this.pose_) {
this.pose_.poseIndex++; this.pose_.poseIndex++;
this.pose_.poseReset = this.send_pose_reset_;
this.send_pose_reset_ = false; }
// Setting the input_state to null tests a slightly different path than // Setting the input_state to null tests a slightly different path than
// the browser tests where if the last input source is removed, the device // the browser tests where if the last input source is removed, the device
// code always sends up an empty array, but it's also valid mojom to send // code always sends up an empty array, but it's also valid mojom to send
// up a null array. // up a null array.
if (this.input_sources_.length > 0) { let input_state = null;
this.pose_.inputState = []; if (this.input_sources_.length > 0) {
for (let i = 0; i < this.input_sources_.length; i++) { input_state = [];
this.pose_.inputState.push(this.input_sources_[i].getInputSourceState()); for (let i = 0; i < this.input_sources_.length; i++) {
} input_state.push(this.input_sources_[i].getInputSourceState());
} else {
this.pose_.inputState = null;
} }
} }
...@@ -542,6 +542,8 @@ class MockRuntime { ...@@ -542,6 +542,8 @@ class MockRuntime {
return Promise.resolve({ return Promise.resolve({
frameData: { frameData: {
pose: this.pose_, pose: this.pose_,
mojoSpaceReset: mojo_space_reset,
inputState: input_state,
timeDelta: { timeDelta: {
microseconds: now, microseconds: now,
}, },
......
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