Line data Source code
1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 :
7 : #include "VRManager.h"
8 : #include "VRManagerParent.h"
9 : #include "gfxVR.h"
10 : #include "mozilla/ClearOnShutdown.h"
11 : #include "mozilla/dom/VRDisplay.h"
12 : #include "mozilla/dom/GamepadEventTypes.h"
13 : #include "mozilla/layers/TextureHost.h"
14 : #include "mozilla/Unused.h"
15 :
16 : #include "gfxPrefs.h"
17 : #include "gfxVR.h"
18 : #if defined(XP_WIN)
19 : #include "gfxVROculus.h"
20 : #endif
21 : #if defined(XP_WIN) || defined(XP_MACOSX) || (defined(XP_LINUX) && !defined(MOZ_WIDGET_ANDROID))
22 : #include "gfxVROpenVR.h"
23 : #include "gfxVROSVR.h"
24 : #endif
25 : #include "gfxVRPuppet.h"
26 : #include "ipc/VRLayerParent.h"
27 :
28 : using namespace mozilla;
29 : using namespace mozilla::gfx;
30 : using namespace mozilla::layers;
31 : using namespace mozilla::gl;
32 :
33 : namespace mozilla {
34 : namespace gfx {
35 :
36 3 : static StaticRefPtr<VRManager> sVRManagerSingleton;
37 :
38 : /*static*/ void
39 3 : VRManager::ManagerInit()
40 : {
41 3 : MOZ_ASSERT(NS_IsMainThread());
42 :
43 3 : if (sVRManagerSingleton == nullptr) {
44 3 : sVRManagerSingleton = new VRManager();
45 3 : ClearOnShutdown(&sVRManagerSingleton);
46 : }
47 3 : }
48 :
49 3 : VRManager::VRManager()
50 : : mInitialized(false)
51 3 : , mVRTestSystemCreated(false)
52 : {
53 3 : MOZ_COUNT_CTOR(VRManager);
54 3 : MOZ_ASSERT(sVRManagerSingleton == nullptr);
55 :
56 6 : RefPtr<VRSystemManager> mgr;
57 :
58 : /**
59 : * We must add the VRDisplayManager's to mManagers in a careful order to
60 : * ensure that we don't detect the same VRDisplay from multiple API's.
61 : *
62 : * Oculus comes first, as it will only enumerate Oculus HMD's and is the
63 : * native interface for Oculus HMD's.
64 : *
65 : * OpenvR comes second, as it is the native interface for HTC Vive
66 : * which is the most common HMD at this time.
67 : *
68 : * OSVR will be used if Oculus SDK and OpenVR don't detect any HMDS,
69 : * to support everyone else.
70 : */
71 :
72 : #if defined(XP_WIN)
73 : // The Oculus runtime is supported only on Windows
74 : mgr = VRSystemManagerOculus::Create();
75 : if (mgr) {
76 : mManagers.AppendElement(mgr);
77 : }
78 : #endif
79 :
80 : #if defined(XP_WIN) || defined(XP_MACOSX) || (defined(XP_LINUX) && !defined(MOZ_WIDGET_ANDROID))
81 : // OpenVR is cross platform compatible
82 3 : mgr = VRSystemManagerOpenVR::Create();
83 3 : if (mgr) {
84 0 : mManagers.AppendElement(mgr);
85 : }
86 :
87 : // OSVR is cross platform compatible
88 3 : mgr = VRSystemManagerOSVR::Create();
89 3 : if (mgr) {
90 0 : mManagers.AppendElement(mgr);
91 : }
92 : #endif
93 : // Enable gamepad extensions while VR is enabled.
94 : // Preference only can be set at the Parent process.
95 3 : if (XRE_IsParentProcess() && gfxPrefs::VREnabled()) {
96 1 : Preferences::SetBool("dom.gamepad.extensions.enabled", true);
97 : }
98 3 : }
99 :
100 0 : VRManager::~VRManager()
101 : {
102 0 : MOZ_ASSERT(NS_IsMainThread());
103 0 : MOZ_ASSERT(!mInitialized);
104 0 : MOZ_COUNT_DTOR(VRManager);
105 0 : }
106 :
107 : void
108 0 : VRManager::Destroy()
109 : {
110 0 : mVRDisplays.Clear();
111 0 : mVRControllers.Clear();
112 0 : for (uint32_t i = 0; i < mManagers.Length(); ++i) {
113 0 : mManagers[i]->Destroy();
114 : }
115 :
116 0 : mInitialized = false;
117 0 : }
118 :
119 : void
120 151 : VRManager::Shutdown()
121 : {
122 151 : mVRDisplays.Clear();
123 151 : mVRControllers.Clear();
124 151 : for (uint32_t i = 0; i < mManagers.Length(); ++i) {
125 0 : mManagers[i]->Shutdown();
126 : }
127 151 : }
128 :
129 : void
130 1 : VRManager::Init()
131 : {
132 1 : mInitialized = true;
133 1 : }
134 :
135 : /* static */VRManager*
136 154 : VRManager::Get()
137 : {
138 154 : MOZ_ASSERT(sVRManagerSingleton != nullptr);
139 :
140 154 : return sVRManagerSingleton;
141 : }
142 :
143 : void
144 3 : VRManager::AddVRManagerParent(VRManagerParent* aVRManagerParent)
145 : {
146 3 : if (mVRManagerParents.IsEmpty()) {
147 1 : Init();
148 : }
149 3 : mVRManagerParents.PutEntry(aVRManagerParent);
150 3 : }
151 :
152 : void
153 0 : VRManager::RemoveVRManagerParent(VRManagerParent* aVRManagerParent)
154 : {
155 0 : mVRManagerParents.RemoveEntry(aVRManagerParent);
156 0 : if (mVRManagerParents.IsEmpty()) {
157 0 : Destroy();
158 : }
159 0 : }
160 :
161 : void
162 151 : VRManager::NotifyVsync(const TimeStamp& aVsyncTimestamp)
163 : {
164 151 : const double kVRDisplayRefreshMaxDuration = 5000; // milliseconds
165 151 : const double kVRDisplayInactiveMaxDuration = 30000; // milliseconds
166 :
167 151 : bool bHaveEventListener = false;
168 151 : bool bHaveControllerListener = false;
169 :
170 455 : for (auto iter = mVRManagerParents.Iter(); !iter.Done(); iter.Next()) {
171 304 : VRManagerParent *vmp = iter.Get()->GetKey();
172 304 : bHaveEventListener |= vmp->HaveEventListener();
173 304 : bHaveControllerListener |= vmp->HaveControllerListener();
174 : }
175 :
176 : // VRDisplayHost::NotifyVSync may modify mVRDisplays, so we iterate
177 : // through a local copy here.
178 302 : nsTArray<RefPtr<VRDisplayHost>> displays;
179 151 : for (auto iter = mVRDisplays.Iter(); !iter.Done(); iter.Next()) {
180 0 : displays.AppendElement(iter.UserData());
181 : }
182 151 : for (const auto& display: displays) {
183 0 : display->NotifyVSync();
184 : }
185 :
186 151 : if (bHaveEventListener) {
187 : // If content has set an EventHandler to be notified of VR display events
188 : // we must continually refresh the VR display enumeration to check
189 : // for events that we must fire such as Window.onvrdisplayconnect
190 : // Note that enumeration itself may activate display hardware, such
191 : // as Oculus, so we only do this when we know we are displaying content
192 : // that is looking for VR displays.
193 0 : if (mLastRefreshTime.IsNull()) {
194 : // This is the first vsync, must refresh VR displays
195 0 : RefreshVRDisplays();
196 0 : if (bHaveControllerListener) {
197 0 : RefreshVRControllers();
198 : }
199 0 : mLastRefreshTime = TimeStamp::Now();
200 : } else {
201 : // We don't have to do this every frame, so check if we
202 : // have refreshed recently.
203 0 : TimeDuration duration = TimeStamp::Now() - mLastRefreshTime;
204 0 : if (duration.ToMilliseconds() > kVRDisplayRefreshMaxDuration) {
205 0 : RefreshVRDisplays();
206 0 : if (bHaveControllerListener) {
207 0 : RefreshVRControllers();
208 : }
209 0 : mLastRefreshTime = TimeStamp::Now();
210 : }
211 : }
212 :
213 0 : if (bHaveControllerListener) {
214 0 : for (const auto& manager: mManagers) {
215 0 : if (!manager->GetIsPresenting()) {
216 0 : manager->HandleInput();
217 : }
218 : }
219 : }
220 : }
221 :
222 : // Shut down the VR devices when not in use
223 151 : if (bHaveEventListener || bHaveControllerListener) {
224 : // We are using a VR device, keep it alive
225 0 : mLastActiveTime = TimeStamp::Now();
226 151 : } else if (mLastActiveTime.IsNull()) {
227 151 : Shutdown();
228 : } else {
229 0 : TimeDuration duration = TimeStamp::Now() - mLastActiveTime;
230 0 : if (duration.ToMilliseconds() > kVRDisplayInactiveMaxDuration) {
231 0 : Shutdown();
232 : }
233 : }
234 151 : }
235 :
236 : void
237 0 : VRManager::NotifyVRVsync(const uint32_t& aDisplayID)
238 : {
239 0 : for (const auto& manager: mManagers) {
240 0 : if (manager->GetIsPresenting()) {
241 0 : manager->HandleInput();
242 : }
243 : }
244 :
245 0 : RefPtr<VRDisplayHost> display = GetDisplay(aDisplayID);
246 0 : if (display) {
247 0 : display->StartFrame();
248 : }
249 :
250 0 : RefreshVRDisplays();
251 0 : }
252 :
253 : void
254 0 : VRManager::RefreshVRDisplays(bool aMustDispatch)
255 : {
256 0 : nsTArray<RefPtr<gfx::VRDisplayHost> > displays;
257 :
258 : /** We don't wish to enumerate the same display from multiple managers,
259 : * so stop as soon as we get a display.
260 : * It is still possible to get multiple displays from a single manager,
261 : * but do not wish to mix-and-match for risk of reporting a duplicate.
262 : *
263 : * XXX - Perhaps there will be a better way to detect duplicate displays
264 : * in the future.
265 : */
266 0 : for (uint32_t i = 0; i < mManagers.Length() && displays.Length() == 0; ++i) {
267 0 : if (mManagers[i]->GetHMDs(displays)) {
268 : // GetHMDs returns true to indicate that no further enumeration from
269 : // other managers should be performed. This prevents erraneous
270 : // redundant enumeration of the same HMD by multiple managers.
271 0 : break;
272 : }
273 : }
274 :
275 0 : bool displayInfoChanged = false;
276 0 : bool displaySetChanged = false;
277 :
278 0 : if (displays.Length() != mVRDisplays.Count()) {
279 : // Catch cases where a VR display has been removed
280 0 : displaySetChanged = true;
281 : }
282 :
283 0 : for (const auto& display: displays) {
284 0 : if (!GetDisplay(display->GetDisplayInfo().GetDisplayID())) {
285 : // This is a new display
286 0 : displaySetChanged = true;
287 0 : break;
288 : }
289 :
290 0 : if (display->CheckClearDisplayInfoDirty()) {
291 : // This display's info has changed
292 0 : displayInfoChanged = true;
293 0 : break;
294 : }
295 : }
296 :
297 : // Rebuild the HashMap if there are additions or removals
298 0 : if (displaySetChanged) {
299 0 : mVRDisplays.Clear();
300 0 : for (const auto& display: displays) {
301 0 : mVRDisplays.Put(display->GetDisplayInfo().GetDisplayID(), display);
302 : }
303 : }
304 :
305 0 : if (displayInfoChanged || displaySetChanged || aMustDispatch) {
306 0 : DispatchVRDisplayInfoUpdate();
307 : }
308 0 : }
309 :
310 : void
311 0 : VRManager::DispatchVRDisplayInfoUpdate()
312 : {
313 0 : nsTArray<VRDisplayInfo> update;
314 0 : GetVRDisplayInfo(update);
315 :
316 0 : for (auto iter = mVRManagerParents.Iter(); !iter.Done(); iter.Next()) {
317 0 : Unused << iter.Get()->GetKey()->SendUpdateDisplayInfo(update);
318 : }
319 0 : }
320 :
321 :
322 : /**
323 : * Get any VR displays that have already been enumerated without
324 : * activating any new devices.
325 : */
326 : void
327 0 : VRManager::GetVRDisplayInfo(nsTArray<VRDisplayInfo>& aDisplayInfo)
328 : {
329 0 : aDisplayInfo.Clear();
330 0 : for (auto iter = mVRDisplays.Iter(); !iter.Done(); iter.Next()) {
331 0 : gfx::VRDisplayHost* display = iter.UserData();
332 0 : aDisplayInfo.AppendElement(VRDisplayInfo(display->GetDisplayInfo()));
333 : }
334 0 : }
335 :
336 : RefPtr<gfx::VRDisplayHost>
337 0 : VRManager::GetDisplay(const uint32_t& aDisplayID)
338 : {
339 0 : RefPtr<gfx::VRDisplayHost> display;
340 0 : if (mVRDisplays.Get(aDisplayID, getter_AddRefs(display))) {
341 0 : return display;
342 : }
343 0 : return nullptr;
344 : }
345 :
346 : void
347 0 : VRManager::SubmitFrame(VRLayerParent* aLayer, layers::PTextureParent* aTexture,
348 : const gfx::Rect& aLeftEyeRect,
349 : const gfx::Rect& aRightEyeRect)
350 : {
351 0 : TextureHost* th = TextureHost::AsTextureHost(aTexture);
352 0 : mLastFrame = th;
353 0 : RefPtr<VRDisplayHost> display = GetDisplay(aLayer->GetDisplayID());
354 0 : if (display) {
355 0 : display->SubmitFrame(aLayer, aTexture, aLeftEyeRect, aRightEyeRect);
356 : }
357 0 : }
358 :
359 : RefPtr<gfx::VRControllerHost>
360 0 : VRManager::GetController(const uint32_t& aControllerID)
361 : {
362 0 : RefPtr<gfx::VRControllerHost> controller;
363 0 : if (mVRControllers.Get(aControllerID, getter_AddRefs(controller))) {
364 0 : return controller;
365 : }
366 0 : return nullptr;
367 : }
368 :
369 : void
370 0 : VRManager::GetVRControllerInfo(nsTArray<VRControllerInfo>& aControllerInfo)
371 : {
372 0 : aControllerInfo.Clear();
373 0 : for (auto iter = mVRControllers.Iter(); !iter.Done(); iter.Next()) {
374 0 : gfx::VRControllerHost* controller = iter.UserData();
375 0 : aControllerInfo.AppendElement(VRControllerInfo(controller->GetControllerInfo()));
376 : }
377 0 : }
378 :
379 : void
380 0 : VRManager::RefreshVRControllers()
381 : {
382 0 : nsTArray<RefPtr<gfx::VRControllerHost>> controllers;
383 :
384 0 : ScanForControllers();
385 :
386 0 : for (uint32_t i = 0; i < mManagers.Length()
387 0 : && controllers.Length() == 0; ++i) {
388 0 : mManagers[i]->GetControllers(controllers);
389 : }
390 :
391 0 : bool controllerInfoChanged = false;
392 :
393 0 : if (controllers.Length() != mVRControllers.Count()) {
394 : // Catch cases where VR controllers has been removed
395 0 : controllerInfoChanged = true;
396 : }
397 :
398 0 : for (const auto& controller: controllers) {
399 0 : if (!GetController(controller->GetControllerInfo().GetControllerID())) {
400 : // This is a new controller
401 0 : controllerInfoChanged = true;
402 0 : break;
403 : }
404 : }
405 :
406 0 : if (controllerInfoChanged) {
407 0 : mVRControllers.Clear();
408 0 : for (const auto& controller: controllers) {
409 0 : mVRControllers.Put(controller->GetControllerInfo().GetControllerID(),
410 0 : controller);
411 : }
412 : }
413 0 : }
414 :
415 : void
416 0 : VRManager::ScanForControllers()
417 : {
418 0 : for (uint32_t i = 0; i < mManagers.Length(); ++i) {
419 0 : mManagers[i]->ScanForControllers();
420 : }
421 0 : }
422 :
423 : void
424 0 : VRManager::RemoveControllers()
425 : {
426 0 : for (uint32_t i = 0; i < mManagers.Length(); ++i) {
427 0 : mManagers[i]->RemoveControllers();
428 : }
429 0 : mVRControllers.Clear();
430 0 : }
431 :
432 : void
433 0 : VRManager::CreateVRTestSystem()
434 : {
435 0 : if (mVRTestSystemCreated) {
436 0 : return;
437 : }
438 :
439 0 : RefPtr<VRSystemManager> mgr = VRSystemManagerPuppet::Create();
440 0 : if (mgr) {
441 0 : mManagers.AppendElement(mgr);
442 0 : mVRTestSystemCreated = true;
443 : }
444 : }
445 :
446 : template<class T>
447 : void
448 0 : VRManager::NotifyGamepadChange(const T& aInfo)
449 : {
450 0 : dom::GamepadChangeEvent e(aInfo);
451 :
452 0 : for (auto iter = mVRManagerParents.Iter(); !iter.Done(); iter.Next()) {
453 0 : Unused << iter.Get()->GetKey()->SendGamepadUpdate(e);
454 : }
455 0 : }
456 :
457 : void
458 0 : VRManager::VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
459 : double aIntensity, double aDuration, uint32_t aPromiseID)
460 :
461 : {
462 0 : for (uint32_t i = 0; i < mManagers.Length(); ++i) {
463 0 : mManagers[i]->VibrateHaptic(aControllerIdx, aHapticIndex,
464 0 : aIntensity, aDuration, aPromiseID);
465 : }
466 0 : }
467 :
468 : void
469 0 : VRManager::StopVibrateHaptic(uint32_t aControllerIdx)
470 : {
471 0 : for (const auto& manager: mManagers) {
472 0 : manager->StopVibrateHaptic(aControllerIdx);
473 : }
474 0 : }
475 :
476 : void
477 0 : VRManager::NotifyVibrateHapticCompleted(uint32_t aPromiseID)
478 : {
479 0 : for (auto iter = mVRManagerParents.Iter(); !iter.Done(); iter.Next()) {
480 0 : Unused << iter.Get()->GetKey()->SendReplyGamepadVibrateHaptic(aPromiseID);
481 : }
482 0 : }
483 :
484 : void
485 0 : VRManager::DispatchSubmitFrameResult(uint32_t aDisplayID, const VRSubmitFrameResultInfo& aResult)
486 : {
487 0 : for (auto iter = mVRManagerParents.Iter(); !iter.Done(); iter.Next()) {
488 0 : Unused << iter.Get()->GetKey()->SendDispatchSubmitFrameResult(aDisplayID, aResult);
489 : }
490 0 : }
491 :
492 : } // namespace gfx
493 : } // namespace mozilla
|