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