Commit bc7ad9d1 authored by Bill Orr's avatar Bill Orr Committed by Commit Bot

Reland "WebXR: Do not provide poses to frames without focus"

This reverts commit 0ad90c2f.

Reason for revert: Found the issue with the broken tests.

Original change's description:
> Revert "WebXR: Do not provide poses to frames without focus"
>
> This reverts commit 666960b1.
>
> Reason for revert: Causing a test bug.  Reverting while I investigate that bug (crbug.com/835047).
>
>
>
> Original change's description:
> > WebXR: Do not provide poses to frames without focus
> >
> > This change plumbs through focus (both blink/frame and device) to XRSessions, so we
> > only call raf callbacks when focused.
> >
> > BUG=813230
> >
> > Change-Id: I0aefdce989f6dd60b4cd0acf1a1477fdb2e845b8
> > Reviewed-on: https://chromium-review.googlesource.com/1011288
> > Reviewed-by: Brandon Jones <bajones@chromium.org>
> > Reviewed-by: David Dorwin <ddorwin@chromium.org>
> > Commit-Queue: Bill Orr <billorr@chromium.org>
> > Cr-Commit-Position: refs/heads/master@{#551842}
>
> TBR=ddorwin@chromium.org,bajones@chromium.org,billorr@chromium.org
>
> # Not skipping CQ checks because original CL landed > 1 day ago.
>
> Bug: 813230
> Change-Id: I5c1e1dcb9aaef3fe46c085d6572cea81673e4789
> Reviewed-on: https://chromium-review.googlesource.com/1020800
> Commit-Queue: Bill Orr <billorr@chromium.org>
> Reviewed-by: Bill Orr <billorr@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#552268}

Change-Id: I065ccb0972a33e553aa73140bd649a939a6547f8
Bug: 813230
Reviewed-on: https://chromium-review.googlesource.com/1022560Reviewed-by: default avatarBrandon Jones <bajones@chromium.org>
Reviewed-by: default avatarBill Orr <billorr@chromium.org>
Commit-Queue: Bill Orr <billorr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#553481}
parent 3e18e29e
......@@ -34,6 +34,7 @@ const char kNoDevicesMessage[] = "No devices found.";
XR::XR(LocalFrame& frame)
: ContextLifecycleObserver(frame.GetDocument()),
FocusChangedObserver(frame.GetPage()),
devices_synced_(false),
binding_(this) {
frame.GetInterfaceProvider().GetInterface(mojo::MakeRequest(&service_));
......@@ -49,6 +50,16 @@ XR::XR(LocalFrame& frame)
WTF::Bind(&XR::OnDevicesSynced, WrapPersistent(this)));
}
void XR::FocusedFrameChanged() {
// Tell devices that focus changed.
for (const auto& device : devices_)
device->OnFrameFocusChanged();
}
bool XR::IsFrameFocused() {
return FocusChangedObserver::IsFrameFocused(GetFrame());
}
ExecutionContext* XR::GetExecutionContext() const {
return ContextLifecycleObserver::GetExecutionContext();
}
......
......@@ -11,6 +11,7 @@
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
#include "third_party/blink/renderer/core/page/focus_changed_observer.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
......@@ -21,7 +22,8 @@ class XRDevice;
class XR final : public EventTargetWithInlineData,
public ContextLifecycleObserver,
public device::mojom::blink::VRServiceClient {
public device::mojom::blink::VRServiceClient,
public FocusChangedObserver {
DEFINE_WRAPPERTYPEINFO();
USING_GARBAGE_COLLECTED_MIXIN(XR);
......@@ -44,16 +46,18 @@ class XR final : public EventTargetWithInlineData,
// ContextLifecycleObserver overrides.
void ContextDestroyed(ExecutionContext*) override;
void Dispose();
void Trace(blink::Visitor*) override;
// FocusChangedObserver overrides.
void FocusedFrameChanged() override;
bool IsFrameFocused();
private:
explicit XR(LocalFrame& frame);
void OnDevicesSynced();
void ResolveRequestDevice();
void Dispose();
bool devices_synced_;
......
......@@ -128,6 +128,7 @@ ScriptPromise XRDevice::requestSession(
}
XRSession* session = new XRSession(this, options.exclusive(), output_context);
sessions_.insert(session);
if (options.exclusive()) {
frameProvider()->BeginExclusiveSession(session, resolver);
......@@ -138,20 +139,48 @@ ScriptPromise XRDevice::requestSession(
return promise;
}
void XRDevice::OnFrameFocusChanged() {
OnFocusChanged();
}
void XRDevice::OnFocusChanged() {
// Tell all sessions that focus changed.
for (const auto& session : sessions_) {
session->OnFocusChanged();
}
if (frame_provider_)
frame_provider_->OnFocusChanged();
}
bool XRDevice::IsFrameFocused() {
return xr_->IsFrameFocused();
}
// TODO: Forward these calls on to the sessions once they've been implemented.
void XRDevice::OnChanged(device::mojom::blink::VRDisplayInfoPtr display_info) {
SetXRDisplayInfo(std::move(display_info));
}
void XRDevice::OnExitPresent() {}
void XRDevice::OnBlur() {}
void XRDevice::OnFocus() {}
void XRDevice::OnBlur() {
// The device is reporting to us that it is blurred. This could happen for a
// variety of reasons, such as browser UI, a different application using the
// headset, or another page entering an exclusive session.
has_device_focus_ = false;
OnFocusChanged();
}
void XRDevice::OnFocus() {
has_device_focus_ = true;
OnFocusChanged();
}
void XRDevice::OnActivate(device::mojom::blink::VRDisplayEventReason,
OnActivateCallback on_handled) {}
void XRDevice::OnDeactivate(device::mojom::blink::VRDisplayEventReason) {}
XRFrameProvider* XRDevice::frameProvider() {
if (!frame_provider_)
if (!frame_provider_) {
frame_provider_ = new XRFrameProvider(this);
}
return frame_provider_;
}
......@@ -173,6 +202,7 @@ void XRDevice::SetXRDisplayInfo(
void XRDevice::Trace(blink::Visitor* visitor) {
visitor->Trace(xr_);
visitor->Trace(frame_provider_);
visitor->Trace(sessions_);
EventTargetWithInlineData::Trace(visitor);
}
......
......@@ -18,6 +18,7 @@ namespace blink {
class XR;
class XRFrameProvider;
class XRSession;
class XRDevice final : public EventTargetWithInlineData,
public device::mojom::blink::VRDisplayClient {
......@@ -40,6 +41,7 @@ class XRDevice final : public EventTargetWithInlineData,
// EventTarget overrides.
ExecutionContext* GetExecutionContext() const override;
const AtomicString& InterfaceName() const override;
void Trace(blink::Visitor*) override;
// XRDisplayClient
void OnChanged(device::mojom::blink::VRDisplayInfoPtr) override;
......@@ -68,17 +70,31 @@ class XRDevice final : public EventTargetWithInlineData,
// depend on it can know when they need to update.
unsigned int xrDisplayInfoPtrId() const { return display_info_id_; }
void Trace(blink::Visitor*) override;
void OnFrameFocusChanged();
// The device may report focus to us - for example if another application is
// using the headset, or some browsing UI is shown, we may not have device
// focus.
bool HasDeviceFocus() { return has_device_focus_; }
bool HasDeviceAndFrameFocus() { return IsFrameFocused() && HasDeviceFocus(); }
private:
void SetXRDisplayInfo(device::mojom::blink::VRDisplayInfoPtr);
const char* checkSessionSupport(const XRSessionCreationOptions&) const;
// There are two components to focus - whether the frame itself has
// traditional focus and whether the device reports that we have focus. These
// are aggregated so we can hand out focus/blur events on sessions and
// determine when to call animation frame callbacks.
void OnFocusChanged();
bool IsFrameFocused();
Member<XR> xr_;
Member<XRFrameProvider> frame_provider_;
HeapHashSet<WeakMember<XRSession>> sessions_;
bool is_external_;
bool supports_exclusive_;
bool has_device_focus_ = true;
device::mojom::blink::VRMagicWindowProviderPtr magic_window_provider_;
device::mojom::blink::VRDisplayHostPtr display_;
......
......@@ -84,7 +84,8 @@ std::unique_ptr<TransformationMatrix> getPoseMatrix(
} // namespace
XRFrameProvider::XRFrameProvider(XRDevice* device) : device_(device) {}
XRFrameProvider::XRFrameProvider(XRDevice* device)
: device_(device), last_has_focus_(device->HasDeviceAndFrameFocus()) {}
void XRFrameProvider::BeginExclusiveSession(XRSession* session,
ScriptPromiseResolver* resolver) {
......@@ -147,6 +148,21 @@ void XRFrameProvider::OnPresentComplete(
pending_exclusive_session_resolver_ = nullptr;
}
void XRFrameProvider::OnFocusChanged() {
bool focus = device_->HasDeviceAndFrameFocus();
// If we are gaining focus, schedule a frame for magic window. This accounts
// for skipping RAFs in ProcessScheduledFrame. Only do this when there are
// magic window sessions but no exclusive session. Note that exclusive
// sessions don't stop scheduling RAFs when focus is lost, so there is no need
// to schedule exclusive frames when focus is acquired.
if (focus && !last_has_focus_ && requesting_sessions_.size() > 0 &&
!exclusive_session_) {
ScheduleNonExclusiveFrame();
}
last_has_focus_ = focus;
}
void XRFrameProvider::OnPresentationProviderConnectionError() {
if (pending_exclusive_session_resolver_) {
DOMException* exception = DOMException::Create(
......@@ -297,6 +313,11 @@ void XRFrameProvider::ProcessScheduledFrame(double timestamp) {
TRACE_EVENT1("gpu", "XRFrameProvider::ProcessScheduledFrame", "frame",
frame_id_);
if (!device_->HasDeviceAndFrameFocus() && !exclusive_session_) {
return; // Not currently focused, so we won't expose poses (except to
// exclusive sessions).
}
if (exclusive_session_can_send_frames_) {
if (frame_pose_ && frame_pose_->input_state.has_value()) {
exclusive_session_->OnInputStateChange(frame_id_,
......
......@@ -39,6 +39,7 @@ class XRFrameProvider final
void UpdateWebGLLayerViewports(XRWebGLLayer*);
void Dispose();
void OnFocusChanged();
virtual void Trace(blink::Visitor*);
......@@ -88,6 +89,7 @@ class XRFrameProvider final
bool vsync_connection_failed_ = false;
base::Optional<gpu::MailboxHolder> buffer_mailbox_holder_;
bool last_has_focus_ = false;
};
} // namespace blink
......
......@@ -90,6 +90,8 @@ XRSession::XRSession(XRDevice* device,
exclusive_(exclusive),
output_context_(output_context),
callback_collection_(device->GetExecutionContext()) {
blurred_ = !HasAppropriateFocus();
// When an output context is provided, monitor it for resize events.
if (output_context_) {
HTMLCanvasElement* canvas = outputContext()->canvas();
......@@ -301,6 +303,22 @@ void XRSession::OnBlur() {
DispatchEvent(XRSessionEvent::Create(EventTypeNames::blur, this));
}
// Exclusive sessions may still not be blurred in headset even if the page isn't
// focused. This prevents the in-headset experience from freezing on an
// external display headset when the user clicks on another tab.
bool XRSession::HasAppropriateFocus() {
return exclusive_ ? device_->HasDeviceFocus()
: device_->HasDeviceAndFrameFocus();
}
void XRSession::OnFocusChanged() {
if (HasAppropriateFocus()) {
OnFocus();
} else {
OnBlur();
}
}
void XRSession::OnFrame(
std::unique_ptr<TransformationMatrix> base_pose_matrix,
const base::Optional<gpu::MailboxHolder>& buffer_mailbox_holder) {
......
......@@ -99,8 +99,7 @@ class XRSession final : public EventTargetWithInlineData {
ExecutionContext* GetExecutionContext() const override;
const AtomicString& InterfaceName() const override;
void OnFocus();
void OnBlur();
void OnFocusChanged();
void OnFrame(std::unique_ptr<TransformationMatrix>,
const base::Optional<gpu::MailboxHolder>&);
void OnInputStateChange(
......@@ -128,6 +127,10 @@ class XRSession final : public EventTargetWithInlineData {
XRInputSourceEvent* CreateInputSourceEvent(const AtomicString&,
XRInputSource*);
void OnFocus();
void OnBlur();
bool HasAppropriateFocus();
const Member<XRDevice> device_;
const bool exclusive_;
const Member<XRPresentationContext> output_context_;
......@@ -142,7 +145,7 @@ class XRSession final : public EventTargetWithInlineData {
double depth_near_ = 0.1;
double depth_far_ = 1000.0;
bool blurred_ = false;
bool blurred_;
bool ended_ = false;
bool pending_frame_ = false;
bool resolving_frame_ = false;
......
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