Line data Source code
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 :
8 : #include "VRManager.h"
9 : #include "VRManagerParent.h"
10 : #include "VRThread.h"
11 : #include "gfxVR.h"
12 : #include "mozilla/ClearOnShutdown.h"
13 : #include "mozilla/dom/VRDisplay.h"
14 : #include "mozilla/dom/GamepadEventTypes.h"
15 : #include "mozilla/layers/TextureHost.h"
16 : #include "mozilla/layers/CompositorThread.h"
17 : #include "mozilla/Unused.h"
18 :
19 : #include "gfxPrefs.h"
20 : #include "gfxVR.h"
21 : #include "gfxVRExternal.h"
22 : #if defined(XP_WIN)
23 : #include "gfxVROculus.h"
24 : #endif
25 : #if defined(XP_WIN) || defined(XP_MACOSX) || (defined(XP_LINUX) && !defined(MOZ_WIDGET_ANDROID))
26 : #include "gfxVROpenVR.h"
27 : #include "gfxVROSVR.h"
28 : #endif
29 :
30 : #include "gfxVRPuppet.h"
31 : #include "ipc/VRLayerParent.h"
32 :
33 : using namespace mozilla;
34 : using namespace mozilla::gfx;
35 : using namespace mozilla::layers;
36 : using namespace mozilla::gl;
37 :
38 : namespace mozilla {
39 : namespace gfx {
40 :
41 1 : static StaticRefPtr<VRManager> sVRManagerSingleton;
42 :
43 : /*static*/ void
44 0 : VRManager::ManagerInit()
45 : {
46 1 : MOZ_ASSERT(NS_IsMainThread());
47 :
48 2 : if (sVRManagerSingleton == nullptr) {
49 0 : sVRManagerSingleton = new VRManager();
50 1 : ClearOnShutdown(&sVRManagerSingleton);
51 : }
52 0 : }
53 :
54 1 : VRManager::VRManager()
55 : : mInitialized(false)
56 : , mVRDisplaysRequested(false)
57 0 : , mVRControllersRequested(false)
58 : {
59 1 : MOZ_COUNT_CTOR(VRManager);
60 0 : MOZ_ASSERT(sVRManagerSingleton == nullptr);
61 :
62 0 : RefPtr<VRSystemManager> mgr;
63 :
64 : /**
65 : * We must add the VRDisplayManager's to mManagers in a careful order to
66 : * ensure that we don't detect the same VRDisplay from multiple API's.
67 : *
68 : * Oculus comes first, as it will only enumerate Oculus HMD's and is the
69 : * native interface for Oculus HMD's.
70 : *
71 : * OpenvR comes second, as it is the native interface for HTC Vive
72 : * which is the most common HMD at this time.
73 : *
74 : * OSVR will be used if Oculus SDK and OpenVR don't detect any HMDS,
75 : * to support everyone else.
76 : */
77 1 : mExternalManager = VRSystemManagerExternal::Create();
78 2 : if (mExternalManager) {
79 0 : mManagers.AppendElement(mExternalManager);
80 : }
81 :
82 : #if defined(XP_WIN)
83 : // The Oculus runtime is supported only on Windows
84 : mgr = VRSystemManagerOculus::Create();
85 : if (mgr) {
86 : mManagers.AppendElement(mgr);
87 : }
88 : #endif
89 :
90 : #if defined(XP_WIN) || defined(XP_MACOSX) || (defined(XP_LINUX) && !defined(MOZ_WIDGET_ANDROID))
91 : // OpenVR is cross platform compatible
92 1 : mgr = VRSystemManagerOpenVR::Create();
93 1 : if (mgr) {
94 0 : mManagers.AppendElement(mgr);
95 : }
96 :
97 : // OSVR is cross platform compatible
98 1 : mgr = VRSystemManagerOSVR::Create();
99 1 : if (mgr) {
100 0 : mManagers.AppendElement(mgr);
101 : }
102 : #endif
103 :
104 : // Enable gamepad extensions while VR is enabled.
105 : // Preference only can be set at the Parent process.
106 1 : if (XRE_IsParentProcess() && gfxPrefs::VREnabled()) {
107 1 : Preferences::SetBool("dom.gamepad.extensions.enabled", true);
108 : }
109 1 : }
110 :
111 0 : VRManager::~VRManager()
112 : {
113 0 : MOZ_ASSERT(NS_IsMainThread());
114 0 : MOZ_ASSERT(!mInitialized);
115 0 : MOZ_COUNT_DTOR(VRManager);
116 0 : }
117 :
118 : void
119 0 : VRManager::Destroy()
120 : {
121 0 : mVRDisplays.Clear();
122 0 : mVRControllers.Clear();
123 0 : for (uint32_t i = 0; i < mManagers.Length(); ++i) {
124 0 : mManagers[i]->Destroy();
125 : }
126 :
127 0 : mInitialized = false;
128 0 : }
129 :
130 : void
131 0 : VRManager::Shutdown()
132 : {
133 0 : mVRDisplays.Clear();
134 0 : mVRControllers.Clear();
135 164 : for (uint32_t i = 0; i < mManagers.Length(); ++i) {
136 0 : mManagers[i]->Shutdown();
137 : }
138 0 : }
139 :
140 : void
141 0 : VRManager::Init()
142 : {
143 0 : mInitialized = true;
144 0 : }
145 :
146 : /* static */VRManager*
147 84 : VRManager::Get()
148 : {
149 168 : MOZ_ASSERT(sVRManagerSingleton != nullptr);
150 :
151 0 : return sVRManagerSingleton;
152 : }
153 :
154 : void
155 2 : VRManager::AddVRManagerParent(VRManagerParent* aVRManagerParent)
156 : {
157 0 : if (mVRManagerParents.IsEmpty()) {
158 1 : Init();
159 : }
160 2 : mVRManagerParents.PutEntry(aVRManagerParent);
161 0 : }
162 :
163 : void
164 0 : VRManager::RemoveVRManagerParent(VRManagerParent* aVRManagerParent)
165 : {
166 0 : mVRManagerParents.RemoveEntry(aVRManagerParent);
167 0 : if (mVRManagerParents.IsEmpty()) {
168 0 : Destroy();
169 : }
170 0 : }
171 :
172 : void
173 82 : VRManager::UpdateRequestedDevices()
174 : {
175 82 : bool bHaveEventListener = false;
176 0 : bool bHaveControllerListener = false;
177 :
178 0 : for (auto iter = mVRManagerParents.Iter(); !iter.Done(); iter.Next()) {
179 328 : VRManagerParent *vmp = iter.Get()->GetKey();
180 0 : bHaveEventListener |= vmp->HaveEventListener();
181 164 : bHaveControllerListener |= vmp->HaveControllerListener();
182 : }
183 :
184 82 : mVRDisplaysRequested = bHaveEventListener;
185 : // We only currently allow controllers to be used when
186 : // also activating a VR display
187 82 : mVRControllersRequested = mVRDisplaysRequested && bHaveControllerListener;
188 0 : }
189 :
190 : /**
191 : * VRManager::NotifyVsync must be called on every 2d vsync (usually at 60hz).
192 : * This must be called even when no WebVR site is active.
193 : * If we don't have a 2d display attached to the system, we can call this
194 : * at the VR display's native refresh rate.
195 : **/
196 : void
197 0 : VRManager::NotifyVsync(const TimeStamp& aVsyncTimestamp)
198 : {
199 82 : MOZ_ASSERT(VRListenerThreadHolder::IsInVRListenerThread());
200 82 : UpdateRequestedDevices();
201 :
202 246 : for (const auto& manager : mManagers) {
203 0 : manager->NotifyVSync();
204 : }
205 :
206 : // We must continually refresh the VR display enumeration to check
207 : // for events that we must fire such as Window.onvrdisplayconnect
208 : // Note that enumeration itself may activate display hardware, such
209 : // as Oculus, so we only do this when we know we are displaying content
210 : // that is looking for VR displays.
211 82 : RefreshVRDisplays();
212 :
213 : // Update state and enumeration of VR controllers
214 82 : RefreshVRControllers();
215 :
216 82 : CheckForInactiveTimeout();
217 82 : }
218 :
219 : void
220 82 : VRManager::CheckForInactiveTimeout()
221 : {
222 : // Shut down the VR devices when not in use
223 82 : if (mVRDisplaysRequested || mVRControllersRequested) {
224 : // We are using a VR device, keep it alive
225 0 : mLastActiveTime = TimeStamp::Now();
226 : }
227 0 : else if (mLastActiveTime.IsNull()) {
228 82 : Shutdown();
229 : }
230 : else {
231 0 : TimeDuration duration = TimeStamp::Now() - mLastActiveTime;
232 0 : if (duration.ToMilliseconds() > gfxPrefs::VRInactiveTimeout()) {
233 0 : Shutdown();
234 : }
235 : }
236 82 : }
237 :
238 : void
239 0 : VRManager::NotifyVRVsync(const uint32_t& aDisplayID)
240 : {
241 0 : MOZ_ASSERT(VRListenerThreadHolder::IsInVRListenerThread());
242 0 : for (const auto& manager: mManagers) {
243 0 : if (manager->GetIsPresenting()) {
244 0 : manager->HandleInput();
245 : }
246 : }
247 :
248 0 : RefPtr<VRDisplayHost> display = GetDisplay(aDisplayID);
249 0 : if (display) {
250 0 : display->StartFrame();
251 : }
252 :
253 0 : RefreshVRDisplays();
254 0 : }
255 :
256 : void
257 0 : VRManager::EnumerateVRDisplays()
258 : {
259 : /**
260 : * Throttle the rate of enumeration to the interval set in
261 : * VRDisplayEnumerateInterval
262 : */
263 0 : if (!mLastDisplayEnumerationTime.IsNull()) {
264 0 : TimeDuration duration = TimeStamp::Now() - mLastDisplayEnumerationTime;
265 0 : if (duration.ToMilliseconds() < gfxPrefs::VRDisplayEnumerateInterval()) {
266 0 : return;
267 : }
268 : }
269 :
270 : /**
271 : * Any VRSystemManager instance may request that no enumeration
272 : * should occur, including enumeration from other VRSystemManager
273 : * instances.
274 : */
275 0 : for (const auto& manager : mManagers) {
276 0 : if (manager->ShouldInhibitEnumeration()) {
277 0 : return;
278 : }
279 : }
280 :
281 : /**
282 : * If we get this far, don't try again until
283 : * the VRDisplayEnumerateInterval elapses
284 : */
285 0 : mLastDisplayEnumerationTime = TimeStamp::Now();
286 :
287 : /**
288 : * VRSystemManagers are inserted into mManagers in
289 : * a strict order of priority. The managers for the
290 : * most device-specialized API's will have a chance
291 : * to enumerate devices before the more generic
292 : * device-agnostic APIs.
293 : */
294 0 : for (const auto& manager : mManagers) {
295 0 : manager->Enumerate();
296 : /**
297 : * After a VRSystemManager::Enumerate is called, it may request
298 : * that further enumeration should stop. This can be used to prevent
299 : * erraneous redundant enumeration of the same HMD by multiple managers.
300 : * XXX - Perhaps there will be a better way to detect duplicate displays
301 : * in the future.
302 : */
303 0 : if (manager->ShouldInhibitEnumeration()) {
304 0 : return;
305 : }
306 : }
307 : }
308 :
309 : void
310 82 : VRManager::RefreshVRDisplays(bool aMustDispatch)
311 : {
312 : /**
313 : * If we aren't viewing WebVR content, don't enumerate
314 : * new hardware, as it will cause some devices to power on
315 : * or interrupt other VR activities.
316 : */
317 82 : if (mVRDisplaysRequested || aMustDispatch) {
318 0 : EnumerateVRDisplays();
319 : }
320 :
321 : /**
322 : * VRSystemManager::GetHMDs will not activate new hardware
323 : * or result in interruption of other VR activities.
324 : * We can call it even when suppressing enumeration to get
325 : * the already-enumerated displays.
326 : */
327 0 : nsTArray<RefPtr<gfx::VRDisplayHost> > displays;
328 0 : for (const auto& manager: mManagers) {
329 0 : manager->GetHMDs(displays);
330 : }
331 :
332 82 : bool displayInfoChanged = false;
333 82 : bool displaySetChanged = false;
334 :
335 164 : if (displays.Length() != mVRDisplays.Count()) {
336 : // Catch cases where a VR display has been removed
337 0 : displaySetChanged = true;
338 : }
339 :
340 246 : for (const auto& display: displays) {
341 0 : if (!GetDisplay(display->GetDisplayInfo().GetDisplayID())) {
342 : // This is a new display
343 : displaySetChanged = true;
344 : break;
345 : }
346 :
347 0 : if (display->CheckClearDisplayInfoDirty()) {
348 : // This display's info has changed
349 : displayInfoChanged = true;
350 : break;
351 : }
352 : }
353 :
354 : // Rebuild the HashMap if there are additions or removals
355 82 : if (displaySetChanged) {
356 0 : mVRDisplays.Clear();
357 0 : for (const auto& display: displays) {
358 0 : mVRDisplays.Put(display->GetDisplayInfo().GetDisplayID(), display);
359 : }
360 : }
361 :
362 82 : if (displayInfoChanged || displaySetChanged || aMustDispatch) {
363 0 : DispatchVRDisplayInfoUpdate();
364 : }
365 0 : }
366 :
367 : void
368 0 : VRManager::DispatchVRDisplayInfoUpdate()
369 : {
370 0 : nsTArray<VRDisplayInfo> update;
371 0 : GetVRDisplayInfo(update);
372 :
373 0 : for (auto iter = mVRManagerParents.Iter(); !iter.Done(); iter.Next()) {
374 0 : Unused << iter.Get()->GetKey()->SendUpdateDisplayInfo(update);
375 : }
376 0 : }
377 :
378 :
379 : /**
380 : * Get any VR displays that have already been enumerated without
381 : * activating any new devices.
382 : */
383 : void
384 0 : VRManager::GetVRDisplayInfo(nsTArray<VRDisplayInfo>& aDisplayInfo)
385 : {
386 0 : aDisplayInfo.Clear();
387 0 : for (auto iter = mVRDisplays.Iter(); !iter.Done(); iter.Next()) {
388 0 : gfx::VRDisplayHost* display = iter.UserData();
389 0 : aDisplayInfo.AppendElement(VRDisplayInfo(display->GetDisplayInfo()));
390 : }
391 0 : }
392 :
393 : RefPtr<gfx::VRDisplayHost>
394 0 : VRManager::GetDisplay(const uint32_t& aDisplayID)
395 : {
396 0 : RefPtr<gfx::VRDisplayHost> display;
397 0 : if (mVRDisplays.Get(aDisplayID, getter_AddRefs(display))) {
398 : return display;
399 : }
400 : return nullptr;
401 : }
402 :
403 : RefPtr<gfx::VRControllerHost>
404 0 : VRManager::GetController(const uint32_t& aControllerID)
405 : {
406 0 : RefPtr<gfx::VRControllerHost> controller;
407 0 : if (mVRControllers.Get(aControllerID, getter_AddRefs(controller))) {
408 : return controller;
409 : }
410 : return nullptr;
411 : }
412 :
413 : void
414 0 : VRManager::GetVRControllerInfo(nsTArray<VRControllerInfo>& aControllerInfo)
415 : {
416 0 : aControllerInfo.Clear();
417 0 : for (auto iter = mVRControllers.Iter(); !iter.Done(); iter.Next()) {
418 0 : gfx::VRControllerHost* controller = iter.UserData();
419 0 : aControllerInfo.AppendElement(VRControllerInfo(controller->GetControllerInfo()));
420 : }
421 0 : }
422 :
423 : void
424 0 : VRManager::RefreshVRControllers()
425 : {
426 0 : ScanForControllers();
427 :
428 0 : nsTArray<RefPtr<gfx::VRControllerHost>> controllers;
429 :
430 246 : for (uint32_t i = 0; i < mManagers.Length()
431 0 : && controllers.Length() == 0; ++i) {
432 0 : mManagers[i]->GetControllers(controllers);
433 : }
434 :
435 82 : bool controllerInfoChanged = false;
436 :
437 164 : if (controllers.Length() != mVRControllers.Count()) {
438 : // Catch cases where VR controllers has been removed
439 0 : controllerInfoChanged = true;
440 : }
441 :
442 0 : for (const auto& controller: controllers) {
443 0 : if (!GetController(controller->GetControllerInfo().GetControllerID())) {
444 : // This is a new controller
445 : controllerInfoChanged = true;
446 : break;
447 : }
448 : }
449 :
450 82 : if (controllerInfoChanged) {
451 0 : mVRControllers.Clear();
452 0 : for (const auto& controller: controllers) {
453 0 : mVRControllers.Put(controller->GetControllerInfo().GetControllerID(),
454 0 : controller);
455 : }
456 : }
457 82 : }
458 :
459 : void
460 0 : VRManager::ScanForControllers()
461 : {
462 : // We don't have to do this every frame, so check if we
463 : // have enumerated recently
464 0 : if (!mLastControllerEnumerationTime.IsNull()) {
465 0 : TimeDuration duration = TimeStamp::Now() - mLastControllerEnumerationTime;
466 0 : if (duration.ToMilliseconds() < gfxPrefs::VRControllerEnumerateInterval()) {
467 0 : return;
468 : }
469 : }
470 :
471 : // Only enumerate controllers once we need them
472 82 : if (!mVRControllersRequested) {
473 : return;
474 : }
475 :
476 0 : for (uint32_t i = 0; i < mManagers.Length(); ++i) {
477 0 : mManagers[i]->ScanForControllers();
478 : }
479 :
480 0 : mLastControllerEnumerationTime = TimeStamp::Now();
481 : }
482 :
483 : void
484 0 : VRManager::RemoveControllers()
485 : {
486 0 : for (uint32_t i = 0; i < mManagers.Length(); ++i) {
487 0 : mManagers[i]->RemoveControllers();
488 : }
489 0 : mVRControllers.Clear();
490 0 : }
491 :
492 : void
493 0 : VRManager::CreateVRTestSystem()
494 : {
495 0 : if (mPuppetManager) {
496 0 : mPuppetManager->ClearTestDisplays();
497 0 : return;
498 : }
499 :
500 0 : mPuppetManager = VRSystemManagerPuppet::Create();
501 0 : mManagers.AppendElement(mPuppetManager);
502 : }
503 :
504 : VRSystemManagerPuppet*
505 0 : VRManager::GetPuppetManager()
506 : {
507 0 : MOZ_ASSERT(mPuppetManager);
508 0 : return mPuppetManager;
509 : }
510 :
511 : VRSystemManagerExternal*
512 0 : VRManager::GetExternalManager()
513 : {
514 0 : MOZ_ASSERT(mExternalManager);
515 0 : return mExternalManager;
516 : }
517 :
518 : template<class T>
519 : void
520 0 : VRManager::NotifyGamepadChange(uint32_t aIndex, const T& aInfo)
521 : {
522 0 : dom::GamepadChangeEventBody body(aInfo);
523 0 : dom::GamepadChangeEvent e(aIndex, dom::GamepadServiceType::VR, body);
524 :
525 0 : for (auto iter = mVRManagerParents.Iter(); !iter.Done(); iter.Next()) {
526 0 : Unused << iter.Get()->GetKey()->SendGamepadUpdate(e);
527 : }
528 0 : }
529 :
530 : void
531 0 : VRManager::VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
532 : double aIntensity, double aDuration,
533 : const VRManagerPromise& aPromise)
534 :
535 : {
536 0 : for (uint32_t i = 0; i < mManagers.Length(); ++i) {
537 0 : mManagers[i]->VibrateHaptic(aControllerIdx, aHapticIndex,
538 0 : aIntensity, aDuration, aPromise);
539 : }
540 0 : }
541 :
542 : void
543 0 : VRManager::StopVibrateHaptic(uint32_t aControllerIdx)
544 : {
545 0 : for (const auto& manager: mManagers) {
546 0 : manager->StopVibrateHaptic(aControllerIdx);
547 : }
548 0 : }
549 :
550 : void
551 0 : VRManager::NotifyVibrateHapticCompleted(const VRManagerPromise& aPromise)
552 : {
553 0 : aPromise.mParent->SendReplyGamepadVibrateHaptic(aPromise.mPromiseID);
554 0 : }
555 :
556 : void
557 0 : VRManager::DispatchSubmitFrameResult(uint32_t aDisplayID, const VRSubmitFrameResultInfo& aResult)
558 : {
559 0 : for (auto iter = mVRManagerParents.Iter(); !iter.Done(); iter.Next()) {
560 0 : Unused << iter.Get()->GetKey()->SendDispatchSubmitFrameResult(aDisplayID, aResult);
561 : }
562 0 : }
563 :
564 : } // namespace gfx
565 : } // namespace mozilla
|