/src/mozilla-central/gfx/vr/ipc/VRManagerParent.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 | | #include "VRManagerParent.h" |
8 | | #include "ipc/VRLayerParent.h" |
9 | | #include "mozilla/gfx/PVRManagerParent.h" |
10 | | #include "mozilla/ipc/ProtocolTypes.h" |
11 | | #include "mozilla/ipc/ProtocolUtils.h" // for IToplevelProtocol |
12 | | #include "mozilla/TimeStamp.h" // for TimeStamp |
13 | | #include "mozilla/Unused.h" |
14 | | #include "VRManager.h" |
15 | | #include "VRThread.h" |
16 | | #include "gfxVRPuppet.h" |
17 | | |
18 | | namespace mozilla { |
19 | | using namespace layers; |
20 | | namespace gfx { |
21 | | |
22 | | VRManagerParent::VRManagerParent(ProcessId aChildProcessId, bool aIsContentChild) |
23 | | : mControllerTestID(1) |
24 | | , mHaveEventListener(false) |
25 | | , mHaveControllerListener(false) |
26 | | , mIsContentChild(aIsContentChild) |
27 | 0 | { |
28 | 0 | MOZ_COUNT_CTOR(VRManagerParent); |
29 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
30 | 0 |
|
31 | 0 | SetOtherProcessId(aChildProcessId); |
32 | 0 | } |
33 | | |
34 | | VRManagerParent::~VRManagerParent() |
35 | 0 | { |
36 | 0 | MOZ_ASSERT(!mVRManagerHolder); |
37 | 0 |
|
38 | 0 | MOZ_COUNT_DTOR(VRManagerParent); |
39 | 0 | } |
40 | | |
41 | | PVRLayerParent* |
42 | | VRManagerParent::AllocPVRLayerParent(const uint32_t& aDisplayID, |
43 | | const uint32_t& aGroup) |
44 | 0 | { |
45 | 0 | RefPtr<VRLayerParent> layer; |
46 | 0 | layer = new VRLayerParent(aDisplayID, |
47 | 0 | aGroup); |
48 | 0 | VRManager* vm = VRManager::Get(); |
49 | 0 | RefPtr<gfx::VRDisplayHost> display = vm->GetDisplay(aDisplayID); |
50 | 0 | if (display) { |
51 | 0 | display->AddLayer(layer); |
52 | 0 | } |
53 | 0 | return layer.forget().take(); |
54 | 0 | } |
55 | | |
56 | | bool |
57 | | VRManagerParent::DeallocPVRLayerParent(PVRLayerParent* actor) |
58 | 0 | { |
59 | 0 | delete actor; |
60 | 0 | return true; |
61 | 0 | } |
62 | | |
63 | | bool |
64 | | VRManagerParent::IsSameProcess() const |
65 | 0 | { |
66 | 0 | return OtherPid() == base::GetCurrentProcId(); |
67 | 0 | } |
68 | | |
69 | | void |
70 | | VRManagerParent::RegisterWithManager() |
71 | 0 | { |
72 | 0 | VRManager* vm = VRManager::Get(); |
73 | 0 | vm->AddVRManagerParent(this); |
74 | 0 | mVRManagerHolder = vm; |
75 | 0 | } |
76 | | |
77 | | void |
78 | | VRManagerParent::UnregisterFromManager() |
79 | 0 | { |
80 | 0 | VRManager* vm = VRManager::Get(); |
81 | 0 | vm->RemoveVRManagerParent(this); |
82 | 0 | mVRManagerHolder = nullptr; |
83 | 0 | } |
84 | | |
85 | | /* static */ bool |
86 | | VRManagerParent::CreateForContent(Endpoint<PVRManagerParent>&& aEndpoint) |
87 | 0 | { |
88 | 0 | MessageLoop* loop = VRListenerThreadHolder::Loop(); |
89 | 0 |
|
90 | 0 | RefPtr<VRManagerParent> vmp = new VRManagerParent(aEndpoint.OtherPid(), true); |
91 | 0 | loop->PostTask(NewRunnableMethod<Endpoint<PVRManagerParent>&&>( |
92 | 0 | "gfx::VRManagerParent::Bind", |
93 | 0 | vmp, |
94 | 0 | &VRManagerParent::Bind, |
95 | 0 | std::move(aEndpoint))); |
96 | 0 |
|
97 | 0 | return true; |
98 | 0 | } |
99 | | |
100 | | void |
101 | | VRManagerParent::Bind(Endpoint<PVRManagerParent>&& aEndpoint) |
102 | 0 | { |
103 | 0 | if (!aEndpoint.Bind(this)) { |
104 | 0 | return; |
105 | 0 | } |
106 | 0 | mSelfRef = this; |
107 | 0 |
|
108 | 0 | RegisterWithManager(); |
109 | 0 | } |
110 | | |
111 | | /*static*/ void |
112 | | VRManagerParent::RegisterVRManagerInVRListenerThread(VRManagerParent* aVRManager) |
113 | 0 | { |
114 | 0 | aVRManager->RegisterWithManager(); |
115 | 0 | } |
116 | | |
117 | | /*static*/ VRManagerParent* |
118 | | VRManagerParent::CreateSameProcess() |
119 | 0 | { |
120 | 0 | MessageLoop* loop = VRListenerThreadHolder::Loop(); |
121 | 0 | RefPtr<VRManagerParent> vmp = new VRManagerParent(base::GetCurrentProcId(), false); |
122 | 0 | vmp->mVRListenerThreadHolder = VRListenerThreadHolder::GetSingleton(); |
123 | 0 | vmp->mSelfRef = vmp; |
124 | 0 | loop->PostTask(NewRunnableFunction("RegisterVRManagerInVRListenerThreadRunnable", |
125 | 0 | RegisterVRManagerInVRListenerThread, vmp.get())); |
126 | 0 | return vmp.get(); |
127 | 0 | } |
128 | | |
129 | | bool |
130 | | VRManagerParent::CreateForGPUProcess(Endpoint<PVRManagerParent>&& aEndpoint) |
131 | 0 | { |
132 | 0 | MessageLoop* loop = VRListenerThreadHolder::Loop(); |
133 | 0 |
|
134 | 0 | RefPtr<VRManagerParent> vmp = new VRManagerParent(aEndpoint.OtherPid(), false); |
135 | 0 | vmp->mVRListenerThreadHolder = VRListenerThreadHolder::GetSingleton(); |
136 | 0 | loop->PostTask(NewRunnableMethod<Endpoint<PVRManagerParent>&&>( |
137 | 0 | "gfx::VRManagerParent::Bind", |
138 | 0 | vmp, |
139 | 0 | &VRManagerParent::Bind, |
140 | 0 | std::move(aEndpoint))); |
141 | 0 | return true; |
142 | 0 | } |
143 | | |
144 | | void |
145 | | VRManagerParent::DeferredDestroy() |
146 | 0 | { |
147 | 0 | mVRListenerThreadHolder = nullptr; |
148 | 0 | mSelfRef = nullptr; |
149 | 0 | } |
150 | | |
151 | | void |
152 | | VRManagerParent::ActorDestroy(ActorDestroyReason why) |
153 | 0 | { |
154 | 0 | UnregisterFromManager(); |
155 | 0 | MessageLoop::current()->PostTask( |
156 | 0 | NewRunnableMethod("gfx::VRManagerParent::DeferredDestroy", |
157 | 0 | this, |
158 | 0 | &VRManagerParent::DeferredDestroy)); |
159 | 0 | } |
160 | | |
161 | | void |
162 | | VRManagerParent::OnChannelConnected(int32_t aPid) |
163 | 0 | { |
164 | 0 | mVRListenerThreadHolder = VRListenerThreadHolder::GetSingleton(); |
165 | 0 | } |
166 | | |
167 | | mozilla::ipc::IPCResult |
168 | | VRManagerParent::RecvRefreshDisplays() |
169 | 0 | { |
170 | 0 | // TODO: Bug 1406327, Launch VR listener thread here. |
171 | 0 | MOZ_ASSERT(VRListenerThreadHolder::IsInVRListenerThread()); |
172 | 0 |
|
173 | 0 | // This is called to refresh the VR Displays for Navigator.GetVRDevices(). |
174 | 0 | // We must pass "true" to VRManager::RefreshVRDisplays() |
175 | 0 | // to ensure that the promise returned by Navigator.GetVRDevices |
176 | 0 | // can resolve even if there are no changes to the VR Displays. |
177 | 0 | VRManager* vm = VRManager::Get(); |
178 | 0 | vm->RefreshVRDisplays(true); |
179 | 0 |
|
180 | 0 | return IPC_OK(); |
181 | 0 | } |
182 | | |
183 | | mozilla::ipc::IPCResult |
184 | | VRManagerParent::RecvResetSensor(const uint32_t& aDisplayID) |
185 | 0 | { |
186 | 0 | VRManager* vm = VRManager::Get(); |
187 | 0 | RefPtr<gfx::VRDisplayHost> display = vm->GetDisplay(aDisplayID); |
188 | 0 | if (display != nullptr) { |
189 | 0 | display->ZeroSensor(); |
190 | 0 | } |
191 | 0 |
|
192 | 0 | return IPC_OK(); |
193 | 0 | } |
194 | | |
195 | | mozilla::ipc::IPCResult |
196 | | VRManagerParent::RecvSetGroupMask(const uint32_t& aDisplayID, const uint32_t& aGroupMask) |
197 | 0 | { |
198 | 0 | VRManager* vm = VRManager::Get(); |
199 | 0 | RefPtr<gfx::VRDisplayHost> display = vm->GetDisplay(aDisplayID); |
200 | 0 | if (display != nullptr) { |
201 | 0 | display->SetGroupMask(aGroupMask); |
202 | 0 | } |
203 | 0 | return IPC_OK(); |
204 | 0 | } |
205 | | |
206 | | bool |
207 | | VRManagerParent::HaveEventListener() |
208 | 0 | { |
209 | 0 | return mHaveEventListener; |
210 | 0 | } |
211 | | |
212 | | bool |
213 | | VRManagerParent::HaveControllerListener() |
214 | 0 | { |
215 | 0 | return mHaveControllerListener; |
216 | 0 | } |
217 | | |
218 | | mozilla::ipc::IPCResult |
219 | | VRManagerParent::RecvSetHaveEventListener(const bool& aHaveEventListener) |
220 | 0 | { |
221 | 0 | mHaveEventListener = aHaveEventListener; |
222 | 0 | return IPC_OK(); |
223 | 0 | } |
224 | | |
225 | | mozilla::ipc::IPCResult |
226 | | VRManagerParent::RecvControllerListenerAdded() |
227 | 0 | { |
228 | 0 | // Force update the available controllers for GamepadManager, |
229 | 0 | // remove the existing controllers and sync them by NotifyVsync(). |
230 | 0 | VRManager* vm = VRManager::Get(); |
231 | 0 | vm->RemoveControllers(); |
232 | 0 | mHaveControllerListener = true; |
233 | 0 | return IPC_OK(); |
234 | 0 | } |
235 | | |
236 | | mozilla::ipc::IPCResult |
237 | | VRManagerParent::RecvControllerListenerRemoved() |
238 | 0 | { |
239 | 0 | mHaveControllerListener = false; |
240 | 0 | VRManager* vm = VRManager::Get(); |
241 | 0 | vm->RemoveControllers(); |
242 | 0 | return IPC_OK(); |
243 | 0 | } |
244 | | |
245 | | mozilla::ipc::IPCResult |
246 | | VRManagerParent::RecvCreateVRTestSystem() |
247 | 0 | { |
248 | 0 | VRManager* vm = VRManager::Get(); |
249 | 0 | vm->CreateVRTestSystem(); |
250 | 0 | // The mControllerTestID is 1 based |
251 | 0 | mControllerTestID = 1; |
252 | 0 | mVRControllerTests.Clear(); |
253 | 0 | return IPC_OK(); |
254 | 0 | } |
255 | | |
256 | | mozilla::ipc::IPCResult |
257 | | VRManagerParent::RecvCreateVRServiceTestDisplay(const nsCString& aID, const uint32_t& aPromiseID) |
258 | 0 | { |
259 | 0 | VRManager* vm = VRManager::Get(); |
260 | 0 | VRSystemManagerPuppet* puppetManager = vm->GetPuppetManager(); |
261 | 0 | uint32_t deviceID = puppetManager->CreateTestDisplay(); |
262 | 0 |
|
263 | 0 | if (SendReplyCreateVRServiceTestDisplay(aID, aPromiseID, deviceID)) { |
264 | 0 | return IPC_OK(); |
265 | 0 | } |
266 | 0 |
|
267 | 0 | return IPC_FAIL(this, "SendReplyCreateVRServiceTestController fail"); |
268 | 0 | } |
269 | | |
270 | | mozilla::ipc::IPCResult |
271 | | VRManagerParent::RecvCreateVRServiceTestController(const nsCString& aID, const uint32_t& aPromiseID) |
272 | 0 | { |
273 | 0 | uint32_t controllerIdx = 1; // ID's are 1 based |
274 | 0 | nsTArray<VRControllerInfo> controllerInfoArray; |
275 | 0 | impl::VRControllerPuppet* controllerPuppet = nullptr; |
276 | 0 | VRManager* vm = VRManager::Get(); |
277 | 0 |
|
278 | 0 | /** |
279 | 0 | * When running headless mochitests on some of our automated test |
280 | 0 | * infrastructure, 2d display vsyncs are not always generated. |
281 | 0 | * In this case, the test controllers can't be created immediately |
282 | 0 | * after the VR display was created as the state of the VR displays |
283 | 0 | * are updated during vsync. |
284 | 0 | * To workaround, we produce a vsync manually. |
285 | 0 | */ |
286 | 0 | vm->NotifyVsync(TimeStamp::Now()); |
287 | 0 |
|
288 | 0 | // Get VRControllerPuppet from VRManager |
289 | 0 | vm->GetVRControllerInfo(controllerInfoArray); |
290 | 0 | for (auto& controllerInfo : controllerInfoArray) { |
291 | 0 | if (controllerInfo.GetType() == VRDeviceType::Puppet) { |
292 | 0 | if (controllerIdx == mControllerTestID) { |
293 | 0 | controllerPuppet = static_cast<impl::VRControllerPuppet*>( |
294 | 0 | vm->GetController(controllerInfo.GetControllerID()).get()); |
295 | 0 | break; |
296 | 0 | } |
297 | 0 | ++controllerIdx; |
298 | 0 | } |
299 | 0 | } |
300 | 0 |
|
301 | 0 | // We might not have a controllerPuppet if the test did |
302 | 0 | // not create a VR display first. |
303 | 0 | if (!controllerPuppet) { |
304 | 0 | // We send a device ID of "0" to indicate failure |
305 | 0 | if (SendReplyCreateVRServiceTestController(aID, aPromiseID, 0)) { |
306 | 0 | return IPC_OK(); |
307 | 0 | } |
308 | 0 | } else { |
309 | 0 | if (!mVRControllerTests.Get(mControllerTestID, nullptr)) { |
310 | 0 | mVRControllerTests.Put(mControllerTestID, controllerPuppet); |
311 | 0 | } |
312 | 0 |
|
313 | 0 | if (SendReplyCreateVRServiceTestController(aID, aPromiseID, mControllerTestID)) { |
314 | 0 | ++mControllerTestID; |
315 | 0 | return IPC_OK(); |
316 | 0 | } |
317 | 0 | } |
318 | 0 |
|
319 | 0 | return IPC_FAIL(this, "SendReplyCreateVRServiceTestController fail"); |
320 | 0 | } |
321 | | |
322 | | mozilla::ipc::IPCResult |
323 | | VRManagerParent::RecvSetDisplayInfoToMockDisplay(const uint32_t& aDeviceID, |
324 | | const VRDisplayInfo& aDisplayInfo) |
325 | 0 | { |
326 | 0 | VRManager* vm = VRManager::Get(); |
327 | 0 | VRSystemManagerPuppet* puppetManager = vm->GetPuppetManager(); |
328 | 0 | puppetManager->SetPuppetDisplayInfo(aDeviceID, aDisplayInfo); |
329 | 0 | return IPC_OK(); |
330 | 0 | } |
331 | | |
332 | | mozilla::ipc::IPCResult |
333 | | VRManagerParent::RecvSetSensorStateToMockDisplay(const uint32_t& aDeviceID, |
334 | | const VRHMDSensorState& aSensorState) |
335 | 0 | { |
336 | 0 | VRManager* vm = VRManager::Get(); |
337 | 0 | VRSystemManagerPuppet* puppetManager = vm->GetPuppetManager(); |
338 | 0 | puppetManager->SetPuppetDisplaySensorState(aDeviceID, aSensorState); |
339 | 0 | return IPC_OK(); |
340 | 0 | } |
341 | | |
342 | | already_AddRefed<impl::VRControllerPuppet> |
343 | | VRManagerParent::GetControllerPuppet(uint32_t aDeviceID) |
344 | 0 | { |
345 | 0 | // aDeviceID for controllers start at 1 and are |
346 | 0 | // used as a key to mVRControllerTests |
347 | 0 | MOZ_ASSERT(aDeviceID > 0); |
348 | 0 | RefPtr<impl::VRControllerPuppet> controllerPuppet; |
349 | 0 | mVRControllerTests.Get(aDeviceID, |
350 | 0 | getter_AddRefs(controllerPuppet)); |
351 | 0 | MOZ_ASSERT(controllerPuppet); |
352 | 0 | return controllerPuppet.forget(); |
353 | 0 | } |
354 | | |
355 | | mozilla::ipc::IPCResult |
356 | | VRManagerParent::RecvNewButtonEventToMockController(const uint32_t& aDeviceID, const long& aButton, |
357 | | const bool& aPressed) |
358 | 0 | { |
359 | 0 | RefPtr<impl::VRControllerPuppet> controllerPuppet = GetControllerPuppet(aDeviceID); |
360 | 0 | if (controllerPuppet) { |
361 | 0 | controllerPuppet->SetButtonPressState(aButton, aPressed); |
362 | 0 | } |
363 | 0 | return IPC_OK(); |
364 | 0 | } |
365 | | |
366 | | mozilla::ipc::IPCResult |
367 | | VRManagerParent::RecvNewAxisMoveEventToMockController(const uint32_t& aDeviceID, const long& aAxis, |
368 | | const double& aValue) |
369 | 0 | { |
370 | 0 | RefPtr<impl::VRControllerPuppet> controllerPuppet = GetControllerPuppet(aDeviceID); |
371 | 0 | if (controllerPuppet) { |
372 | 0 | controllerPuppet->SetAxisMoveState(aAxis, aValue); |
373 | 0 | } |
374 | 0 | return IPC_OK(); |
375 | 0 | } |
376 | | |
377 | | mozilla::ipc::IPCResult |
378 | | VRManagerParent::RecvNewPoseMoveToMockController(const uint32_t& aDeviceID, |
379 | | const GamepadPoseState& pose) |
380 | 0 | { |
381 | 0 | RefPtr<impl::VRControllerPuppet> controllerPuppet = GetControllerPuppet(aDeviceID); |
382 | 0 | if (controllerPuppet) { |
383 | 0 | controllerPuppet->SetPoseMoveState(pose); |
384 | 0 | } |
385 | 0 | return IPC_OK(); |
386 | 0 | } |
387 | | |
388 | | mozilla::ipc::IPCResult |
389 | | VRManagerParent::RecvVibrateHaptic(const uint32_t& aControllerIdx, |
390 | | const uint32_t& aHapticIndex, |
391 | | const double& aIntensity, |
392 | | const double& aDuration, |
393 | | const uint32_t& aPromiseID) |
394 | 0 | { |
395 | 0 | VRManager* vm = VRManager::Get(); |
396 | 0 | VRManagerPromise promise(this, aPromiseID); |
397 | 0 |
|
398 | 0 | vm->VibrateHaptic(aControllerIdx, aHapticIndex, aIntensity, |
399 | 0 | aDuration, promise); |
400 | 0 | return IPC_OK(); |
401 | 0 | } |
402 | | |
403 | | mozilla::ipc::IPCResult |
404 | | VRManagerParent::RecvStopVibrateHaptic(const uint32_t& aControllerIdx) |
405 | 0 | { |
406 | 0 | VRManager* vm = VRManager::Get(); |
407 | 0 | vm->StopVibrateHaptic(aControllerIdx); |
408 | 0 | return IPC_OK(); |
409 | 0 | } |
410 | | |
411 | | bool |
412 | | VRManagerParent::SendGamepadUpdate(const GamepadChangeEvent& aGamepadEvent) |
413 | 0 | { |
414 | 0 | // GamepadManager only exists at the content process |
415 | 0 | // or the same process in non-e10s mode. |
416 | 0 | if (mHaveControllerListener && |
417 | 0 | (mIsContentChild || IsSameProcess())) { |
418 | 0 | return PVRManagerParent::SendGamepadUpdate(aGamepadEvent); |
419 | 0 | } |
420 | 0 | |
421 | 0 | return true; |
422 | 0 | } |
423 | | |
424 | | bool |
425 | | VRManagerParent::SendReplyGamepadVibrateHaptic(const uint32_t& aPromiseID) |
426 | 0 | { |
427 | 0 | // GamepadManager only exists at the content process |
428 | 0 | // or the same process in non-e10s mode. |
429 | 0 | if (mHaveControllerListener && |
430 | 0 | (mIsContentChild || IsSameProcess())) { |
431 | 0 | return PVRManagerParent::SendReplyGamepadVibrateHaptic(aPromiseID); |
432 | 0 | } |
433 | 0 | |
434 | 0 | return true; |
435 | 0 | } |
436 | | |
437 | | mozilla::ipc::IPCResult |
438 | | VRManagerParent::RecvStartVRNavigation(const uint32_t& aDeviceID) |
439 | 0 | { |
440 | 0 | VRManager* vm = VRManager::Get(); |
441 | 0 | vm->StartVRNavigation(aDeviceID); |
442 | 0 | return IPC_OK(); |
443 | 0 | } |
444 | | |
445 | | mozilla::ipc::IPCResult |
446 | | VRManagerParent::RecvStopVRNavigation(const uint32_t& aDeviceID, const TimeDuration& aTimeout) |
447 | 0 | { |
448 | 0 | VRManager* vm = VRManager::Get(); |
449 | 0 | vm->StopVRNavigation(aDeviceID, aTimeout); |
450 | 0 | return IPC_OK(); |
451 | 0 | } |
452 | | |
453 | | } // namespace gfx |
454 | | } // namespace mozilla |