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(
mojom::XRInputSourceStatePtr input_state = GetInputSourceState();
if (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.
frame_data->hit_test_subscription_results =
arcore_->GetHitTestSubscriptionResults(
mojo::ConvertTo<gfx::Transform>(frame_data->pose),
frame_data->pose->input_state);
frame_data->input_state);
}
// Get anchors data, including anchors created this frame.
......
......@@ -930,11 +930,11 @@ void GvrSchedulerDelegate::SendVSync(device::mojom::VRPosePtr pose,
// Process all events. Check for ones we wish to react to.
gvr::Event 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");
pose->input_state = std::move(input_states_);
frame_data->input_state = std::move(input_states_);
frame_data->pose = std::move(pose);
......
......@@ -62,13 +62,10 @@ mojom::XRFrameDataPtr OculusRenderLoop::GetNextFrameData() {
sensor_time_ = ovr_GetTimeInSeconds();
frame_data->time_delta = base::TimeDelta::FromSecondsD(predicted_time);
mojom::VRPosePtr pose =
mojo::ConvertTo<mojom::VRPosePtr>(state.HeadPose.ThePose);
frame_data->pose = mojo::ConvertTo<mojom::VRPosePtr>(state.HeadPose.ThePose);
last_render_pose_ = state.HeadPose.ThePose;
DCHECK(pose);
pose->input_state = GetInputState(state);
frame_data->pose = std::move(pose);
frame_data->input_state = GetInputState(state);
return frame_data;
}
......
......@@ -173,30 +173,24 @@ void OpenVRRenderLoop::OnSessionStart() {
LogViewerType(type);
}
mojom::VRPosePtr OpenVRRenderLoop::GetPose() {
mojom::XRFrameDataPtr OpenVRRenderLoop::GetNextFrameData() {
mojom::XRFrameDataPtr frame_data = mojom::XRFrameData::New();
frame_data->frame_id = next_frame_id_;
if (openvr_) {
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>(
frame_data->pose = mojo::ConvertTo<mojom::VRPosePtr>(
rendering_poses[vr::k_unTrackedDeviceIndex_Hmd]);
// Update WebXR input sources.
DCHECK(pose);
pose->input_state =
frame_data->input_state =
GetInputState(rendering_poses, vr::k_unMaxTrackedDeviceCount);
return pose;
}
mojom::XRFrameDataPtr OpenVRRenderLoop::GetNextFrameData() {
mojom::XRFrameDataPtr frame_data = mojom::XRFrameData::New();
frame_data->frame_id = next_frame_id_;
if (openvr_) {
frame_data->pose = GetPose();
vr::Compositor_FrameTiming timing;
timing.m_nSize = sizeof(vr::Compositor_FrameTiming);
bool valid_time = openvr_->GetCompositor()->GetFrameTiming(&timing);
......
......@@ -43,7 +43,6 @@ class OpenVRRenderLoop : public XRCompositorCommon {
bool SubmitCompositedFrame() override;
// Helpers to implement XRDeviceAbstraction.
mojom::VRPosePtr GetPose();
std::vector<mojom::XRInputSourceStatePtr> GetInputState(
vr::TrackedDevicePose_t* poses,
uint32_t count);
......
......@@ -38,10 +38,11 @@ mojom::XRFrameDataPtr OpenXrRenderLoop::GetNextFrameData() {
frame_data->time_delta =
base::TimeDelta::FromNanoseconds(openxr_->GetPredictedDisplayTime());
frame_data->pose = mojom::VRPose::New();
frame_data->pose->input_state =
frame_data->input_state =
input_helper_->GetInputState(openxr_->GetPredictedDisplayTime());
frame_data->pose = mojom::VRPose::New();
base::Optional<gfx::Quaternion> orientation;
base::Optional<gfx::Point3F> position;
if (XR_SUCCEEDED(openxr_->GetHeadPose(
......
......@@ -188,8 +188,9 @@ struct VRFieldOfView {
float right_degrees;
};
// A display's position, orientation, velocity, and acceleration state at the
// given timestamp.
// An entity's pose. Used by entities for which either position or orientation
// may sometimes not be known. Also supports those poses where the position may
// be emulated and this is worth telling consumers.
struct VRPose {
gfx.mojom.Quaternion? orientation;
gfx.mojom.Point3F? position;
......@@ -197,15 +198,6 @@ struct VRPose {
// True when position is estimated by something like a neck or arm model.
// False when position is based on sensors tracking a 6DoF pose.
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
......@@ -426,6 +418,16 @@ struct XRFrameData {
// for rendering.
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
// The frame_id maps frame data to a frame arriving from the compositor. IDs
......@@ -445,6 +447,13 @@ struct XRFrameData {
VREyeParameters? left_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
// 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
......
......@@ -873,7 +873,7 @@ mojom::XRFrameDataPtr MixedRealityRenderLoop::GetNextFrameData() {
current_display_info_.Clone()));
}
ret->pose->input_state =
ret->input_state =
input_helper_->GetInputState(anchor_origin_.get(), timestamp_.get());
ret->pose->emulated_position = emulated_position_;
......
......@@ -397,12 +397,12 @@ void XRFrameProvider::ProcessScheduledFrame(
if (!immersive_session_ || immersive_session_->ended())
return;
if (frame_pose && frame_pose->pose_reset) {
immersive_session_->OnPoseReset();
if (frame_data && frame_data->mojo_space_reset) {
immersive_session_->OnMojoSpaceReset();
}
// Check if immersive session is still set as OnPoseReset may have allowed a
// ForceEndSession to be triggered.
// Check if immersive session is still set as |OnMojoSpaceReset| may have
// allowed a ForceEndSession to be triggered.
if (!immersive_session_ || immersive_session_->ended()) {
return;
}
......@@ -457,8 +457,8 @@ void XRFrameProvider::ProcessScheduledFrame(
if (session->ended())
continue;
if (frame_pose && frame_pose->pose_reset) {
session->OnPoseReset();
if (frame_data && frame_data->mojo_space_reset) {
session->OnMojoSpaceReset();
}
// If the pose reset caused us to end, we should stop processing.
......
......@@ -1398,10 +1398,10 @@ void XRSession::UpdatePresentationFrameState(
emulated_position_ = emulated_position;
// Process XR input sources
if (frame_pose) {
if (frame_data) {
base::span<const device::mojom::blink::XRInputSourceStatePtr> input_states;
if (frame_pose->input_state.has_value())
input_states = frame_pose->input_state.value();
if (frame_data->input_state.has_value())
input_states = frame_data->input_state.value();
OnInputStateChangeInternal(frame_id, input_states);
......@@ -1689,7 +1689,7 @@ void XRSession::RemoveTransientInputSource(XRInputSource* input_source) {
event_type_names::kInputsourceschange, this, {}, {input_source}));
}
void XRSession::OnPoseReset() {
void XRSession::OnMojoSpaceReset() {
for (const auto& reference_space : reference_spaces_) {
reference_space->OnReset();
}
......
......@@ -203,7 +203,7 @@ class XRSession final
void AddTransientInputSource(XRInputSource* input_source);
void RemoveTransientInputSource(XRInputSource* input_source);
void OnPoseReset();
void OnMojoSpaceReset();
const device::mojom::blink::VRDisplayInfoPtr& GetVRDisplayInfo() const {
return display_info_;
......
......@@ -216,7 +216,7 @@ class MockRuntime {
this.pose_ = null;
this.next_frame_id_ = 0;
this.bounds_ = null;
this.send_pose_reset_ = false;
this.send_mojo_space_reset_ = false;
this.service_ = service;
......@@ -370,7 +370,7 @@ class MockRuntime {
}
simulateResetPose() {
this.send_pose_reset_ = true;
this.send_mojo_space_reset_ = true;
}
simulateInputSourceConnection(fakeInputSourceInit) {
......@@ -514,22 +514,22 @@ class MockRuntime {
// XRFrameDataProvider implementation.
getFrameData() {
let mojo_space_reset = this.send_mojo_space_reset_;
this.send_mojo_space_reset_ = false;
if (this.pose_) {
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
// 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
// up a null array.
let input_state = null;
if (this.input_sources_.length > 0) {
this.pose_.inputState = [];
input_state = [];
for (let i = 0; i < this.input_sources_.length; i++) {
this.pose_.inputState.push(this.input_sources_[i].getInputSourceState());
}
} else {
this.pose_.inputState = null;
input_state.push(this.input_sources_[i].getInputSourceState());
}
}
......@@ -542,6 +542,8 @@ class MockRuntime {
return Promise.resolve({
frameData: {
pose: this.pose_,
mojoSpaceReset: mojo_space_reset,
inputState: input_state,
timeDelta: {
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