1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "VRManagerChild.h"
8
9 #include "VRLayerChild.h"
10 #include "VRManagerParent.h"
11 #include "VRThread.h"
12 #include "VRDisplayClient.h"
13 #include "nsGlobalWindow.h"
14 #include "mozilla/ProfilerMarkers.h"
15 #include "mozilla/StaticPtr.h"
16 #include "mozilla/layers/CompositorThread.h" // for CompositorThread
17 #include "mozilla/dom/Navigator.h"
18 #include "mozilla/dom/VREventObserver.h"
19 #include "mozilla/dom/WebXRBinding.h"
20 #include "mozilla/dom/WindowBinding.h" // for FrameRequestCallback
21 #include "mozilla/dom/XRSystem.h"
22 #include "mozilla/dom/XRFrame.h"
23 #include "mozilla/dom/ContentChild.h"
24 #include "nsContentUtils.h"
25 #include "mozilla/dom/GamepadManager.h"
26 #include "mozilla/ipc/Endpoint.h"
27 #include "mozilla/layers/SyncObject.h"
28 #include "mozilla/layers/TextureForwarder.h"
29
30 using namespace mozilla::dom;
31
32 namespace {
33 const nsTArray<RefPtr<mozilla::gfx::VRManagerEventObserver>>::index_type
34 kNoIndex = nsTArray<RefPtr<mozilla::gfx::VRManagerEventObserver>>::NoIndex;
35 } // namespace
36
37 namespace mozilla {
38 namespace gfx {
39
40 static StaticRefPtr<VRManagerChild> sVRManagerChildSingleton;
41 static StaticRefPtr<VRManagerParent> sVRManagerParentSingleton;
42
43 static TimeStamp sMostRecentFrameEnd;
44 static TimeDuration sAverageFrameInterval;
45
ReleaseVRManagerParentSingleton()46 void ReleaseVRManagerParentSingleton() { sVRManagerParentSingleton = nullptr; }
47
VRManagerChild()48 VRManagerChild::VRManagerChild()
49 : mRuntimeCapabilities(VRDisplayCapabilityFlags::Cap_None),
50 mFrameRequestCallbackCounter(0),
51 mWaitingForEnumeration(false),
52 mBackend(layers::LayersBackend::LAYERS_NONE) {
53 MOZ_ASSERT(NS_IsMainThread());
54
55 mStartTimeStamp = TimeStamp::Now();
56 AddRef();
57 }
58
~VRManagerChild()59 VRManagerChild::~VRManagerChild() { MOZ_ASSERT(NS_IsMainThread()); }
60
61 /*static*/
IdentifyTextureHost(const TextureFactoryIdentifier & aIdentifier)62 void VRManagerChild::IdentifyTextureHost(
63 const TextureFactoryIdentifier& aIdentifier) {
64 if (sVRManagerChildSingleton) {
65 sVRManagerChildSingleton->mBackend = aIdentifier.mParentBackend;
66 }
67 }
68
GetBackendType() const69 layers::LayersBackend VRManagerChild::GetBackendType() const {
70 return mBackend;
71 }
72
73 /*static*/
Get()74 VRManagerChild* VRManagerChild::Get() {
75 MOZ_ASSERT(sVRManagerChildSingleton);
76 return sVRManagerChildSingleton;
77 }
78
79 /* static */
IsCreated()80 bool VRManagerChild::IsCreated() { return !!sVRManagerChildSingleton; }
81
82 /* static */
IsPresenting()83 bool VRManagerChild::IsPresenting() {
84 if (!VRManagerChild::IsCreated()) {
85 return false;
86 }
87
88 nsTArray<RefPtr<VRDisplayClient>> displays;
89 sVRManagerChildSingleton->GetVRDisplays(displays);
90
91 bool result = false;
92 for (auto& display : displays) {
93 result |= display->IsPresenting();
94 }
95 return result;
96 }
97
GetIdleDeadlineHint(TimeStamp aDefault)98 TimeStamp VRManagerChild::GetIdleDeadlineHint(TimeStamp aDefault) {
99 MOZ_ASSERT(NS_IsMainThread());
100 if (!VRManagerChild::IsCreated() || sMostRecentFrameEnd.IsNull()) {
101 return aDefault;
102 }
103
104 TimeStamp idleEnd = sMostRecentFrameEnd + sAverageFrameInterval;
105 return idleEnd < aDefault ? idleEnd : aDefault;
106 }
107
108 /* static */
InitForContent(Endpoint<PVRManagerChild> && aEndpoint)109 bool VRManagerChild::InitForContent(Endpoint<PVRManagerChild>&& aEndpoint) {
110 MOZ_ASSERT(NS_IsMainThread());
111
112 RefPtr<VRManagerChild> child(new VRManagerChild());
113 if (!aEndpoint.Bind(child)) {
114 return false;
115 }
116 sVRManagerChildSingleton = child;
117 return true;
118 }
119
120 /*static*/
InitSameProcess()121 void VRManagerChild::InitSameProcess() {
122 MOZ_ASSERT(NS_IsMainThread());
123 MOZ_ASSERT(!sVRManagerChildSingleton);
124
125 sVRManagerChildSingleton = new VRManagerChild();
126 sVRManagerParentSingleton = VRManagerParent::CreateSameProcess();
127 sVRManagerChildSingleton->Open(sVRManagerParentSingleton->GetIPCChannel(),
128 CompositorThread(), mozilla::ipc::ChildSide);
129 }
130
131 /* static */
InitWithGPUProcess(Endpoint<PVRManagerChild> && aEndpoint)132 void VRManagerChild::InitWithGPUProcess(Endpoint<PVRManagerChild>&& aEndpoint) {
133 MOZ_ASSERT(NS_IsMainThread());
134 MOZ_ASSERT(!sVRManagerChildSingleton);
135
136 sVRManagerChildSingleton = new VRManagerChild();
137 if (!aEndpoint.Bind(sVRManagerChildSingleton)) {
138 MOZ_CRASH("Couldn't Open() Compositor channel.");
139 }
140 }
141
142 /*static*/
ShutDown()143 void VRManagerChild::ShutDown() {
144 MOZ_ASSERT(NS_IsMainThread());
145 if (!sVRManagerChildSingleton) {
146 return;
147 }
148 sVRManagerChildSingleton->Close();
149 sVRManagerChildSingleton = nullptr;
150 }
151
ActorDealloc()152 void VRManagerChild::ActorDealloc() { Release(); }
153
ActorDestroy(ActorDestroyReason aReason)154 void VRManagerChild::ActorDestroy(ActorDestroyReason aReason) {
155 if (sVRManagerChildSingleton == this) {
156 sVRManagerChildSingleton = nullptr;
157 }
158 }
159
AllocPVRLayerChild(const uint32_t & aDisplayID,const uint32_t & aGroup)160 PVRLayerChild* VRManagerChild::AllocPVRLayerChild(const uint32_t& aDisplayID,
161 const uint32_t& aGroup) {
162 return VRLayerChild::CreateIPDLActor();
163 }
164
DeallocPVRLayerChild(PVRLayerChild * actor)165 bool VRManagerChild::DeallocPVRLayerChild(PVRLayerChild* actor) {
166 return VRLayerChild::DestroyIPDLActor(actor);
167 }
168
UpdateDisplayInfo(const VRDisplayInfo & aDisplayInfo)169 void VRManagerChild::UpdateDisplayInfo(const VRDisplayInfo& aDisplayInfo) {
170 nsTArray<uint32_t> disconnectedDisplays;
171 nsTArray<uint32_t> connectedDisplays;
172
173 const nsTArray<RefPtr<VRDisplayClient>> prevDisplays(mDisplays.Clone());
174
175 // Check if any displays have been disconnected
176 for (auto& display : prevDisplays) {
177 bool found = false;
178 if (aDisplayInfo.GetDisplayID() != 0) {
179 if (display->GetDisplayInfo().GetDisplayID() ==
180 aDisplayInfo.GetDisplayID()) {
181 found = true;
182 break;
183 }
184 }
185 if (!found) {
186 // In order to make the current VRDisplay can continue to apply for the
187 // newest VRDisplayInfo, we need to exit presentionation before
188 // disconnecting.
189 if (display->IsPresentationGenerationCurrent()) {
190 NotifyPresentationGenerationChangedInternal(
191 display->GetDisplayInfo().GetDisplayID());
192
193 RefPtr<VRManagerChild> vm = VRManagerChild::Get();
194 vm->FireDOMVRDisplayPresentChangeEvent(
195 display->GetDisplayInfo().GetDisplayID());
196 }
197 display->NotifyDisconnected();
198 disconnectedDisplays.AppendElement(
199 display->GetDisplayInfo().GetDisplayID());
200 }
201 }
202
203 // mDisplays could be a hashed container for more scalability, but not worth
204 // it now as we expect < 10 entries.
205 nsTArray<RefPtr<VRDisplayClient>> displays;
206 if (aDisplayInfo.GetDisplayID() != 0) {
207 bool isNewDisplay = true;
208 for (auto& display : prevDisplays) {
209 const VRDisplayInfo& prevInfo = display->GetDisplayInfo();
210 if (prevInfo.GetDisplayID() == aDisplayInfo.GetDisplayID()) {
211 if (aDisplayInfo.GetIsConnected() && !prevInfo.GetIsConnected()) {
212 connectedDisplays.AppendElement(aDisplayInfo.GetDisplayID());
213 }
214 if (!aDisplayInfo.GetIsConnected() && prevInfo.GetIsConnected()) {
215 disconnectedDisplays.AppendElement(aDisplayInfo.GetDisplayID());
216 }
217 // MOZ_KnownLive because 'prevDisplays' is guaranteed to keep it alive.
218 //
219 // This can go away once
220 // https://bugzilla.mozilla.org/show_bug.cgi?id=1620312 is fixed.
221 MOZ_KnownLive(display)->UpdateDisplayInfo(aDisplayInfo);
222 displays.AppendElement(display);
223 isNewDisplay = false;
224 break;
225 }
226 }
227 if (isNewDisplay) {
228 displays.AppendElement(new VRDisplayClient(aDisplayInfo));
229 connectedDisplays.AppendElement(aDisplayInfo.GetDisplayID());
230 }
231 }
232
233 mDisplays = std::move(displays);
234
235 // We wish to fire the events only after mDisplays is updated
236 for (uint32_t displayID : disconnectedDisplays) {
237 FireDOMVRDisplayDisconnectEvent(displayID);
238 }
239
240 for (uint32_t displayID : connectedDisplays) {
241 FireDOMVRDisplayConnectEvent(displayID);
242 }
243 }
244
RuntimeSupportsVR() const245 bool VRManagerChild::RuntimeSupportsVR() const {
246 return bool(mRuntimeCapabilities & VRDisplayCapabilityFlags::Cap_ImmersiveVR);
247 }
RuntimeSupportsAR() const248 bool VRManagerChild::RuntimeSupportsAR() const {
249 return bool(mRuntimeCapabilities & VRDisplayCapabilityFlags::Cap_ImmersiveAR);
250 }
RuntimeSupportsInline() const251 bool VRManagerChild::RuntimeSupportsInline() const {
252 return bool(mRuntimeCapabilities & VRDisplayCapabilityFlags::Cap_Inline);
253 }
254
RecvUpdateRuntimeCapabilities(const VRDisplayCapabilityFlags & aCapabilities)255 mozilla::ipc::IPCResult VRManagerChild::RecvUpdateRuntimeCapabilities(
256 const VRDisplayCapabilityFlags& aCapabilities) {
257 mRuntimeCapabilities = aCapabilities;
258 nsContentUtils::AddScriptRunner(NewRunnableMethod<>(
259 "gfx::VRManagerChild::NotifyRuntimeCapabilitiesUpdatedInternal", this,
260 &VRManagerChild::NotifyRuntimeCapabilitiesUpdatedInternal));
261 return IPC_OK();
262 }
263
NotifyRuntimeCapabilitiesUpdatedInternal()264 void VRManagerChild::NotifyRuntimeCapabilitiesUpdatedInternal() {
265 const nsTArray<RefPtr<VRManagerEventObserver>> listeners = mListeners.Clone();
266 for (auto& listener : listeners) {
267 listener->NotifyDetectRuntimesCompleted();
268 }
269 }
270
RecvUpdateDisplayInfo(const VRDisplayInfo & aDisplayInfo)271 mozilla::ipc::IPCResult VRManagerChild::RecvUpdateDisplayInfo(
272 const VRDisplayInfo& aDisplayInfo) {
273 UpdateDisplayInfo(aDisplayInfo);
274 for (auto& windowId : mNavigatorCallbacks) {
275 /** We must call NotifyVRDisplaysUpdated for every
276 * window's Navigator in mNavigatorCallbacks to ensure that
277 * the promise returned by Navigator.GetVRDevices
278 * can resolve. This must happen even if no changes
279 * to VRDisplays have been detected here.
280 */
281 nsGlobalWindowInner* window =
282 nsGlobalWindowInner::GetInnerWindowWithId(windowId);
283 if (!window) {
284 continue;
285 }
286 dom::Navigator* nav = window->Navigator();
287 if (!nav) {
288 continue;
289 }
290 nav->NotifyVRDisplaysUpdated();
291 }
292 mNavigatorCallbacks.Clear();
293 if (mWaitingForEnumeration) {
294 nsContentUtils::AddScriptRunner(NewRunnableMethod<>(
295 "gfx::VRManagerChild::NotifyEnumerationCompletedInternal", this,
296 &VRManagerChild::NotifyEnumerationCompletedInternal));
297 mWaitingForEnumeration = false;
298 }
299 return IPC_OK();
300 }
301
RecvNotifyPuppetCommandBufferCompleted(bool aSuccess)302 mozilla::ipc::IPCResult VRManagerChild::RecvNotifyPuppetCommandBufferCompleted(
303 bool aSuccess) {
304 RefPtr<dom::Promise> promise = mRunPuppetPromise;
305 mRunPuppetPromise = nullptr;
306 if (aSuccess) {
307 promise->MaybeResolve(JS::UndefinedHandleValue);
308 } else {
309 promise->MaybeRejectWithUndefined();
310 }
311 return IPC_OK();
312 }
313
RecvNotifyPuppetResetComplete()314 mozilla::ipc::IPCResult VRManagerChild::RecvNotifyPuppetResetComplete() {
315 nsTArray<RefPtr<dom::Promise>> promises;
316 promises.AppendElements(mResetPuppetPromises);
317 mResetPuppetPromises.Clear();
318 for (const auto& promise : promises) {
319 promise->MaybeResolve(JS::UndefinedHandleValue);
320 }
321 return IPC_OK();
322 }
323
RunPuppet(const nsTArray<uint64_t> & aBuffer,dom::Promise * aPromise,ErrorResult & aRv)324 void VRManagerChild::RunPuppet(const nsTArray<uint64_t>& aBuffer,
325 dom::Promise* aPromise, ErrorResult& aRv) {
326 if (mRunPuppetPromise) {
327 // We only allow one puppet script to run simultaneously.
328 // The prior promise must be resolved before running a new
329 // script.
330 aRv.Throw(NS_ERROR_INVALID_ARG);
331 return;
332 }
333 if (!SendRunPuppet(aBuffer)) {
334 aRv.Throw(NS_ERROR_FAILURE);
335 return;
336 }
337 mRunPuppetPromise = aPromise;
338 }
339
ResetPuppet(dom::Promise * aPromise,ErrorResult & aRv)340 void VRManagerChild::ResetPuppet(dom::Promise* aPromise, ErrorResult& aRv) {
341 if (!SendResetPuppet()) {
342 aRv.Throw(NS_ERROR_FAILURE);
343 return;
344 }
345 mResetPuppetPromises.AppendElement(aPromise);
346 }
347
GetVRDisplays(nsTArray<RefPtr<VRDisplayClient>> & aDisplays)348 void VRManagerChild::GetVRDisplays(
349 nsTArray<RefPtr<VRDisplayClient>>& aDisplays) {
350 aDisplays = mDisplays.Clone();
351 }
352
RefreshVRDisplaysWithCallback(uint64_t aWindowId)353 bool VRManagerChild::RefreshVRDisplaysWithCallback(uint64_t aWindowId) {
354 bool success = SendRefreshDisplays();
355 if (success) {
356 mNavigatorCallbacks.AppendElement(aWindowId);
357 }
358 return success;
359 }
360
EnumerateVRDisplays()361 bool VRManagerChild::EnumerateVRDisplays() {
362 bool success = SendRefreshDisplays();
363 if (success) {
364 mWaitingForEnumeration = true;
365 }
366 return success;
367 }
368
DetectRuntimes()369 void VRManagerChild::DetectRuntimes() { Unused << SendDetectRuntimes(); }
370
CreateVRLayer(uint32_t aDisplayID,nsISerialEventTarget * aTarget,uint32_t aGroup)371 PVRLayerChild* VRManagerChild::CreateVRLayer(uint32_t aDisplayID,
372 nsISerialEventTarget* aTarget,
373 uint32_t aGroup) {
374 PVRLayerChild* vrLayerChild = AllocPVRLayerChild(aDisplayID, aGroup);
375 // Do the DOM labeling.
376 if (aTarget) {
377 SetEventTargetForActor(vrLayerChild, aTarget);
378 MOZ_ASSERT(vrLayerChild->GetActorEventTarget());
379 }
380 return SendPVRLayerConstructor(vrLayerChild, aDisplayID, aGroup);
381 }
382
Call(const DOMHighResTimeStamp & aTimeStamp)383 void VRManagerChild::XRFrameRequest::Call(
384 const DOMHighResTimeStamp& aTimeStamp) {
385 if (mCallback) {
386 RefPtr<mozilla::dom::FrameRequestCallback> callback = mCallback;
387 callback->Call(aTimeStamp);
388 } else {
389 RefPtr<mozilla::dom::XRFrameRequestCallback> callback = mXRCallback;
390 RefPtr<mozilla::dom::XRFrame> frame = mXRFrame;
391 callback->Call(aTimeStamp, *frame);
392 }
393 }
394
ScheduleFrameRequestCallback(mozilla::dom::FrameRequestCallback & aCallback,int32_t * aHandle)395 nsresult VRManagerChild::ScheduleFrameRequestCallback(
396 mozilla::dom::FrameRequestCallback& aCallback, int32_t* aHandle) {
397 if (mFrameRequestCallbackCounter == INT32_MAX) {
398 // Can't increment without overflowing; bail out
399 return NS_ERROR_NOT_AVAILABLE;
400 }
401 int32_t newHandle = ++mFrameRequestCallbackCounter;
402
403 mFrameRequestCallbacks.AppendElement(XRFrameRequest(aCallback, newHandle));
404
405 *aHandle = newHandle;
406 return NS_OK;
407 }
408
CancelFrameRequestCallback(int32_t aHandle)409 void VRManagerChild::CancelFrameRequestCallback(int32_t aHandle) {
410 // mFrameRequestCallbacks is stored sorted by handle
411 mFrameRequestCallbacks.RemoveElementSorted(aHandle);
412 }
413
RunFrameRequestCallbacks()414 void VRManagerChild::RunFrameRequestCallbacks() {
415 AUTO_PROFILER_TRACING_MARKER("VR", "RunFrameRequestCallbacks", GRAPHICS);
416
417 TimeStamp nowTime = TimeStamp::Now();
418 mozilla::TimeDuration duration = nowTime - mStartTimeStamp;
419 DOMHighResTimeStamp timeStamp = duration.ToMilliseconds();
420
421 if (!sMostRecentFrameEnd.IsNull()) {
422 TimeDuration frameInterval = nowTime - sMostRecentFrameEnd;
423 if (sAverageFrameInterval.IsZero()) {
424 sAverageFrameInterval = frameInterval;
425 } else {
426 // Calculate the average interval between frame end and next frame start.
427 // Apply some smoothing to make it more stable.
428 const double smooth = 0.9;
429 sAverageFrameInterval = sAverageFrameInterval.MultDouble(smooth) +
430 frameInterval.MultDouble(1.0 - smooth);
431 }
432 }
433
434 nsTArray<XRFrameRequest> callbacks;
435 callbacks.AppendElements(mFrameRequestCallbacks);
436 mFrameRequestCallbacks.Clear();
437 for (auto& callback : callbacks) {
438 // The FrameRequest copied into the on-stack array holds a strong ref to its
439 // mCallback and there's nothing that can drop that ref until we return.
440 MOZ_KnownLive(callback.mCallback)->Call(timeStamp);
441 }
442
443 if (IsPresenting()) {
444 sMostRecentFrameEnd = TimeStamp::Now();
445 }
446 }
447
NotifyPresentationGenerationChanged(uint32_t aDisplayID)448 void VRManagerChild::NotifyPresentationGenerationChanged(uint32_t aDisplayID) {
449 nsContentUtils::AddScriptRunner(NewRunnableMethod<uint32_t>(
450 "gfx::VRManagerChild::NotifyPresentationGenerationChangedInternal", this,
451 &VRManagerChild::NotifyPresentationGenerationChangedInternal,
452 aDisplayID));
453 }
454
FireDOMVRDisplayMountedEvent(uint32_t aDisplayID)455 void VRManagerChild::FireDOMVRDisplayMountedEvent(uint32_t aDisplayID) {
456 nsContentUtils::AddScriptRunner(NewRunnableMethod<uint32_t>(
457 "gfx::VRManagerChild::FireDOMVRDisplayMountedEventInternal", this,
458 &VRManagerChild::FireDOMVRDisplayMountedEventInternal, aDisplayID));
459 }
460
FireDOMVRDisplayUnmountedEvent(uint32_t aDisplayID)461 void VRManagerChild::FireDOMVRDisplayUnmountedEvent(uint32_t aDisplayID) {
462 nsContentUtils::AddScriptRunner(NewRunnableMethod<uint32_t>(
463 "gfx::VRManagerChild::FireDOMVRDisplayUnmountedEventInternal", this,
464 &VRManagerChild::FireDOMVRDisplayUnmountedEventInternal, aDisplayID));
465 }
466
FireDOMVRDisplayConnectEvent(uint32_t aDisplayID)467 void VRManagerChild::FireDOMVRDisplayConnectEvent(uint32_t aDisplayID) {
468 nsContentUtils::AddScriptRunner(NewRunnableMethod<uint32_t>(
469 "gfx::VRManagerChild::FireDOMVRDisplayConnectEventInternal", this,
470 &VRManagerChild::FireDOMVRDisplayConnectEventInternal, aDisplayID));
471 }
472
FireDOMVRDisplayDisconnectEvent(uint32_t aDisplayID)473 void VRManagerChild::FireDOMVRDisplayDisconnectEvent(uint32_t aDisplayID) {
474 nsContentUtils::AddScriptRunner(NewRunnableMethod<uint32_t>(
475 "gfx::VRManagerChild::FireDOMVRDisplayDisconnectEventInternal", this,
476 &VRManagerChild::FireDOMVRDisplayDisconnectEventInternal, aDisplayID));
477 }
478
FireDOMVRDisplayPresentChangeEvent(uint32_t aDisplayID)479 void VRManagerChild::FireDOMVRDisplayPresentChangeEvent(uint32_t aDisplayID) {
480 nsContentUtils::AddScriptRunner(NewRunnableMethod<uint32_t>(
481 "gfx::VRManagerChild::FireDOMVRDisplayPresentChangeEventInternal", this,
482 &VRManagerChild::FireDOMVRDisplayPresentChangeEventInternal, aDisplayID));
483
484 if (!IsPresenting()) {
485 sMostRecentFrameEnd = TimeStamp();
486 sAverageFrameInterval = 0;
487 }
488 }
489
FireDOMVRDisplayMountedEventInternal(uint32_t aDisplayID)490 void VRManagerChild::FireDOMVRDisplayMountedEventInternal(uint32_t aDisplayID) {
491 // Iterate over a copy of mListeners, as dispatched events may modify it.
492 for (auto& listener : mListeners.Clone()) {
493 listener->NotifyVRDisplayMounted(aDisplayID);
494 }
495 }
496
FireDOMVRDisplayUnmountedEventInternal(uint32_t aDisplayID)497 void VRManagerChild::FireDOMVRDisplayUnmountedEventInternal(
498 uint32_t aDisplayID) {
499 // Iterate over a copy of mListeners, as dispatched events may modify it.
500 for (auto& listener : mListeners.Clone()) {
501 listener->NotifyVRDisplayUnmounted(aDisplayID);
502 }
503 }
504
FireDOMVRDisplayConnectEventInternal(uint32_t aDisplayID)505 void VRManagerChild::FireDOMVRDisplayConnectEventInternal(uint32_t aDisplayID) {
506 // Iterate over a copy of mListeners, as dispatched events may modify it.
507 for (auto& listener : mListeners.Clone()) {
508 listener->NotifyVRDisplayConnect(aDisplayID);
509 }
510 }
511
FireDOMVRDisplayDisconnectEventInternal(uint32_t aDisplayID)512 void VRManagerChild::FireDOMVRDisplayDisconnectEventInternal(
513 uint32_t aDisplayID) {
514 // Iterate over a copy of mListeners, as dispatched events may modify it.
515 for (auto& listener : mListeners.Clone()) {
516 listener->NotifyVRDisplayDisconnect(aDisplayID);
517 }
518 }
519
FireDOMVRDisplayPresentChangeEventInternal(uint32_t aDisplayID)520 void VRManagerChild::FireDOMVRDisplayPresentChangeEventInternal(
521 uint32_t aDisplayID) {
522 // Iterate over a copy of mListeners, as dispatched events may modify it.
523 for (auto& listener : mListeners.Clone()) {
524 // MOZ_KnownLive because 'listeners' is guaranteed to keep it alive.
525 //
526 // This can go away once
527 // https://bugzilla.mozilla.org/show_bug.cgi?id=1620312 is fixed.
528 MOZ_KnownLive(listener)->NotifyVRDisplayPresentChange(aDisplayID);
529 }
530 }
531
FireDOMVRDisplayConnectEventsForLoadInternal(uint32_t aDisplayID,VRManagerEventObserver * aObserver)532 void VRManagerChild::FireDOMVRDisplayConnectEventsForLoadInternal(
533 uint32_t aDisplayID, VRManagerEventObserver* aObserver) {
534 aObserver->NotifyVRDisplayConnect(aDisplayID);
535 }
536
NotifyPresentationGenerationChangedInternal(uint32_t aDisplayID)537 void VRManagerChild::NotifyPresentationGenerationChangedInternal(
538 uint32_t aDisplayID) {
539 for (auto& listener : mListeners.Clone()) {
540 listener->NotifyPresentationGenerationChanged(aDisplayID);
541 }
542 }
543
NotifyEnumerationCompletedInternal()544 void VRManagerChild::NotifyEnumerationCompletedInternal() {
545 for (auto& listener : mListeners.Clone()) {
546 listener->NotifyEnumerationCompleted();
547 }
548 }
549
FireDOMVRDisplayConnectEventsForLoad(VRManagerEventObserver * aObserver)550 void VRManagerChild::FireDOMVRDisplayConnectEventsForLoad(
551 VRManagerEventObserver* aObserver) {
552 // We need to fire the VRDisplayConnect event when a page is loaded
553 // for each VR Display that has already been enumerated
554 for (const auto& display : mDisplays.Clone()) {
555 const VRDisplayInfo& info = display->GetDisplayInfo();
556 if (info.GetIsConnected()) {
557 nsContentUtils::AddScriptRunner(NewRunnableMethod<
558 uint32_t, RefPtr<VRManagerEventObserver>>(
559 "gfx::VRManagerChild::FireDOMVRDisplayConnectEventsForLoadInternal",
560 this, &VRManagerChild::FireDOMVRDisplayConnectEventsForLoadInternal,
561 info.GetDisplayID(), aObserver));
562 }
563 }
564 }
565
AddListener(VRManagerEventObserver * aObserver)566 void VRManagerChild::AddListener(VRManagerEventObserver* aObserver) {
567 MOZ_ASSERT(aObserver);
568
569 if (mListeners.IndexOf(aObserver) != kNoIndex) {
570 return; // already exists
571 }
572
573 mListeners.AppendElement(aObserver);
574 if (mListeners.Length() == 1) {
575 Unused << SendSetHaveEventListener(true);
576 }
577 }
578
RemoveListener(VRManagerEventObserver * aObserver)579 void VRManagerChild::RemoveListener(VRManagerEventObserver* aObserver) {
580 MOZ_ASSERT(aObserver);
581
582 mListeners.RemoveElement(aObserver);
583 if (mListeners.IsEmpty()) {
584 Unused << SendSetHaveEventListener(false);
585 }
586 }
587
StartActivity()588 void VRManagerChild::StartActivity() { Unused << SendStartActivity(); }
589
StopActivity()590 void VRManagerChild::StopActivity() {
591 for (auto& listener : mListeners) {
592 if (!listener->GetStopActivityStatus()) {
593 // We are still showing VR in the active window.
594 return;
595 }
596 }
597
598 Unused << SendStopActivity();
599 }
600
HandleFatalError(const char * aMsg) const601 void VRManagerChild::HandleFatalError(const char* aMsg) const {
602 dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherPid());
603 }
604
AddPromise(const uint32_t & aID,dom::Promise * aPromise)605 void VRManagerChild::AddPromise(const uint32_t& aID, dom::Promise* aPromise) {
606 MOZ_ASSERT(!mGamepadPromiseList.Contains(aID));
607 mGamepadPromiseList.InsertOrUpdate(aID, RefPtr{aPromise});
608 }
609
GetVRAPIMode(uint32_t aDisplayID) const610 gfx::VRAPIMode VRManagerChild::GetVRAPIMode(uint32_t aDisplayID) const {
611 for (auto& display : mDisplays) {
612 if (display->GetDisplayInfo().GetDisplayID() == aDisplayID) {
613 return display->GetXRAPIMode();
614 }
615 }
616 return VRAPIMode::WebXR;
617 }
618
RecvReplyGamepadVibrateHaptic(const uint32_t & aPromiseID)619 mozilla::ipc::IPCResult VRManagerChild::RecvReplyGamepadVibrateHaptic(
620 const uint32_t& aPromiseID) {
621 // VRManagerChild could be at other processes, but GamepadManager
622 // only exists at the content process or the same process
623 // in non-e10s mode.
624 MOZ_ASSERT(XRE_IsContentProcess() || IsSameProcess());
625
626 RefPtr<dom::Promise> p;
627 if (!mGamepadPromiseList.Get(aPromiseID, getter_AddRefs(p))) {
628 MOZ_CRASH("We should always have a promise.");
629 }
630
631 p->MaybeResolve(true);
632 mGamepadPromiseList.Remove(aPromiseID);
633 return IPC_OK();
634 }
635
636 } // namespace gfx
637 } // namespace mozilla
638