Commit 3a89f919 authored by Jacob DeWitt's avatar Jacob DeWitt Committed by Commit Bot

End XRSession when data provider is disconnected.

There are slightly different code paths to handle the disconnect for
immersive and non-immersive sessions. There can only be one immersive
session, but there can be multiple non-immersive sessions and they all
use the same magic window provider as their data provider.

Bug: 937906
Change-Id: I71f05fa2d854c2654744e818d407e4b94a2fd95e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1628269Reviewed-by: default avatarBill Orr <billorr@chromium.org>
Reviewed-by: default avatarAlexander Cooper <alcooper@chromium.org>
Commit-Queue: Jacob DeWitt <jacde@chromium.org>
Cr-Commit-Position: refs/heads/master@{#663821}
parent a53cda46
...@@ -138,6 +138,17 @@ XRFrameProvider* XR::frameProvider() { ...@@ -138,6 +138,17 @@ XRFrameProvider* XR::frameProvider() {
return frame_provider_; return frame_provider_;
} }
bool XR::CanRequestNonImmersiveFrameData() const {
return !!magic_window_provider_;
}
void XR::GetNonImmersiveFrameData(
device::mojom::blink::XRFrameDataRequestOptionsPtr options,
device::mojom::blink::XRFrameDataProvider::GetFrameDataCallback callback) {
DCHECK(CanRequestNonImmersiveFrameData());
magic_window_provider_->GetFrameData(std::move(options), std::move(callback));
}
const device::mojom::blink::XREnvironmentIntegrationProviderAssociatedPtr& const device::mojom::blink::XREnvironmentIntegrationProviderAssociatedPtr&
XR::xrEnvironmentProviderPtr() { XR::xrEnvironmentProviderPtr() {
return environment_provider_; return environment_provider_;
...@@ -492,6 +503,8 @@ void XR::OnRequestSessionReturned( ...@@ -492,6 +503,8 @@ void XR::OnRequestSessionReturned(
} }
} else { } else {
magic_window_provider_.Bind(std::move(session_ptr->data_provider)); magic_window_provider_.Bind(std::move(session_ptr->data_provider));
magic_window_provider_.set_connection_error_handler(WTF::Bind(
&XR::OnMagicWindowProviderDisconnect, WrapWeakPersistent(this)));
} }
query->resolver->Resolve(session); query->resolver->Resolve(session);
...@@ -609,6 +622,17 @@ void XR::OnEnvironmentProviderDisconnect() { ...@@ -609,6 +622,17 @@ void XR::OnEnvironmentProviderDisconnect() {
environment_provider_.reset(); environment_provider_.reset();
} }
// Ends all non-immersive sessions when the magic window provider got
// disconnected.
void XR::OnMagicWindowProviderDisconnect() {
for (auto& session : sessions_) {
if (!session->immersive() && !session->ended()) {
session->ForceEnd();
}
}
magic_window_provider_.reset();
}
void XR::Trace(blink::Visitor* visitor) { void XR::Trace(blink::Visitor* visitor) {
visitor->Trace(pending_mode_queries_); visitor->Trace(pending_mode_queries_);
visitor->Trace(pending_session_requests_); visitor->Trace(pending_session_requests_);
......
...@@ -42,10 +42,11 @@ class XR final : public EventTargetWithInlineData, ...@@ -42,10 +42,11 @@ class XR final : public EventTargetWithInlineData,
XRFrameProvider* frameProvider(); XRFrameProvider* frameProvider();
const device::mojom::blink::XRFrameDataProviderPtr& xrMagicWindowProviderPtr() bool CanRequestNonImmersiveFrameData() const;
const { void GetNonImmersiveFrameData(
return magic_window_provider_; device::mojom::blink::XRFrameDataRequestOptionsPtr,
} device::mojom::blink::XRFrameDataProvider::GetFrameDataCallback);
const device::mojom::blink::XREnvironmentIntegrationProviderAssociatedPtr& const device::mojom::blink::XREnvironmentIntegrationProviderAssociatedPtr&
xrEnvironmentProviderPtr(); xrEnvironmentProviderPtr();
...@@ -118,6 +119,7 @@ class XR final : public EventTargetWithInlineData, ...@@ -118,6 +119,7 @@ class XR final : public EventTargetWithInlineData,
void OnDeviceDisconnect(); void OnDeviceDisconnect();
void OnEnvironmentProviderDisconnect(); void OnEnvironmentProviderDisconnect();
void OnMagicWindowProviderDisconnect();
bool pending_device_ = false; bool pending_device_ = false;
......
...@@ -106,12 +106,13 @@ void XRFrameProvider::BeginImmersiveSession( ...@@ -106,12 +106,13 @@ void XRFrameProvider::BeginImmersiveSession(
immersive_session_ = session; immersive_session_ = session;
immersive_data_provider_.Bind(std::move(session_ptr->data_provider)); immersive_data_provider_.Bind(std::move(session_ptr->data_provider));
immersive_data_provider_.set_connection_error_handler(WTF::Bind(
&XRFrameProvider::OnProviderConnectionError, WrapWeakPersistent(this)));
presentation_provider_.Bind( presentation_provider_.Bind(
std::move(session_ptr->submit_frame_sink->provider)); std::move(session_ptr->submit_frame_sink->provider));
presentation_provider_.set_connection_error_handler( presentation_provider_.set_connection_error_handler(WTF::Bind(
WTF::Bind(&XRFrameProvider::OnPresentationProviderConnectionError, &XRFrameProvider::OnProviderConnectionError, WrapWeakPersistent(this)));
WrapWeakPersistent(this)));
frame_transport_->BindSubmitFrameClient( frame_transport_->BindSubmitFrameClient(
std::move(session_ptr->submit_frame_sink->client_request)); std::move(session_ptr->submit_frame_sink->client_request));
...@@ -135,7 +136,9 @@ void XRFrameProvider::OnFocusChanged() { ...@@ -135,7 +136,9 @@ void XRFrameProvider::OnFocusChanged() {
last_has_focus_ = focus; last_has_focus_ = focus;
} }
void XRFrameProvider::OnPresentationProviderConnectionError() { // Ends the immersive session when the presentation or immersive data provider
// got disconnected.
void XRFrameProvider::OnProviderConnectionError() {
presentation_provider_.reset(); presentation_provider_.reset();
immersive_data_provider_.reset(); immersive_data_provider_.reset();
if (vsync_connection_failed_) if (vsync_connection_failed_)
...@@ -235,8 +238,8 @@ void XRFrameProvider::ScheduleNonImmersiveFrame( ...@@ -235,8 +238,8 @@ void XRFrameProvider::ScheduleNonImmersiveFrame(
// If we have a Magic Window provider, request frame data and flag that // If we have a Magic Window provider, request frame data and flag that
// we're waiting for it. If not, clear any pose data, so that // we're waiting for it. If not, clear any pose data, so that
// ProcessScheduledFrame handles it appropriately. // ProcessScheduledFrame handles it appropriately.
if (xr_->xrMagicWindowProviderPtr()) { if (xr_->CanRequestNonImmersiveFrameData()) {
xr_->xrMagicWindowProviderPtr()->GetFrameData( xr_->GetNonImmersiveFrameData(
std::move(options), WTF::Bind(&XRFrameProvider::OnNonImmersiveFrameData, std::move(options), WTF::Bind(&XRFrameProvider::OnNonImmersiveFrameData,
WrapWeakPersistent(this))); WrapWeakPersistent(this)));
} else { } else {
......
...@@ -60,7 +60,7 @@ class XRFrameProvider final ...@@ -60,7 +60,7 @@ class XRFrameProvider final
void ScheduleNonImmersiveFrame( void ScheduleNonImmersiveFrame(
device::mojom::blink::XRFrameDataRequestOptionsPtr options); device::mojom::blink::XRFrameDataRequestOptionsPtr options);
void OnPresentationProviderConnectionError(); void OnProviderConnectionError();
void ProcessScheduledFrame(device::mojom::blink::XRFrameDataPtr frame_data, void ProcessScheduledFrame(device::mojom::blink::XRFrameDataPtr frame_data,
double high_res_now_ms); double high_res_now_ms);
......
...@@ -340,12 +340,15 @@ class MockRuntime { ...@@ -340,12 +340,15 @@ class MockRuntime {
this.environmentProviderBinding_.close(); this.environmentProviderBinding_.close();
} }
closeDataProvider() {
this.dataProviderBinding_.close();
}
updateSessionGeometry(frame_size, display_rotation) { updateSessionGeometry(frame_size, display_rotation) {
// This function must exist to ensure that calls to it do not crash, but we // This function must exist to ensure that calls to it do not crash, but we
// do not have any use for this data at present. // do not have any use for this data at present.
} }
// Utility function // Utility function
requestRuntimeSession(sessionOptions) { requestRuntimeSession(sessionOptions) {
return this.runtimeSupportsSession(sessionOptions).then((result) => { return this.runtimeSupportsSession(sessionOptions).then((result) => {
...@@ -366,7 +369,7 @@ class MockRuntime { ...@@ -366,7 +369,7 @@ class MockRuntime {
let dataProviderPtr = new device.mojom.XRFrameDataProviderPtr(); let dataProviderPtr = new device.mojom.XRFrameDataProviderPtr();
let dataProviderRequest = mojo.makeRequest(dataProviderPtr); let dataProviderRequest = mojo.makeRequest(dataProviderPtr);
let dataProviderBinding = new mojo.Binding( this.dataProviderBinding_ = new mojo.Binding(
device.mojom.XRFrameDataProvider, this, dataProviderRequest); device.mojom.XRFrameDataProvider, this, dataProviderRequest);
let clientRequest = mojo.makeRequest(this.sessionClient_); let clientRequest = mojo.makeRequest(this.sessionClient_);
......
<!DOCTYPE html>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
<script src="file:///gen/device/vr/public/mojom/vr_service.mojom.js"></script>
<script src="../external/wpt/resources/chromium/webxr-test.js"></script>
<script src="../external/wpt/webxr/resources/webxr_test_constants.js"></script>
<script src="../xr/resources/xr-internal-device-mocking.js"></script>
<script src="../xr/resources/xr-test-utils.js"></script>
<script src="../xr/resources/test-constants.js"></script>
<canvas id="webgl-canvas"></canvas>
<script>
let testName = "Immersive session ends if data provider disconnects.";
let fakeDeviceInitParams = { supportsImmersive: true };
let requestSessionModes = ['immersive-vr'];
let testFunction = function(session, t, fakeDeviceController) {
return new Promise((resolve) => {
// Session must have a baseLayer or frame requests will be ignored.
session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) });
session.addEventListener('end', () => resolve());
// Request an animation frame to ensure that everything has time to get
// initialized/connected and avoid a race-condition failure with the data
// binding not being able to get closed.
session.requestAnimationFrame(() => {
fakeDeviceController.closeDataProvider();
session.requestAnimationFrame(() => {});
});
});
}
xr_session_promise_test(
testFunction, fakeDeviceInitParams, requestSessionModes, testName);
</script>
<!DOCTYPE html>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
<script src="file:///gen/device/vr/public/mojom/vr_service.mojom.js"></script>
<script src="../external/wpt/resources/chromium/webxr-test.js"></script>
<script src="../external/wpt/webxr/resources/webxr_test_constants.js"></script>
<script src="../xr/resources/xr-internal-device-mocking.js"></script>
<script src="../xr/resources/xr-test-utils.js"></script>
<script src="../xr/resources/test-constants.js"></script>
<canvas id="webgl-canvas"></canvas>
<script>
let testName = "Inline session ends if magic window data provider disconnects.";
let fakeDeviceInitParams = { supportsImmersive: false };
let requestSessionModes = ['inline'];
let testFunction = function(session, t, fakeDeviceController) {
return new Promise((resolve) => {
// Session must have a baseLayer or frame requests will be ignored.
// outputContext is also required for inline sessions.
session.updateRenderState({
baseLayer: new XRWebGLLayer(session, gl),
outputContext: getOutputContext()
});
session.addEventListener('end', () => resolve());
// Request an animation frame to ensure that everything has time to get
// initialized/connected and avoid a race-condition failure with the data
// binding not being able to get closed.
session.requestAnimationFrame(() => {
fakeDeviceController.closeDataProvider();
session.requestAnimationFrame(() => {});
});
});
}
xr_session_promise_test(
testFunction, fakeDeviceInitParams, requestSessionModes, testName);
</script>
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