Backed out 6 changesets (bug 1843477) for causing hazards failures. CLOSED TREE
[gecko.git] / gfx / vr / VRDisplayClient.cpp
blob914fb05893c34c94f38f2c0299d5d75e0f805d7f
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/. */
7 #include <math.h>
9 #include "prlink.h"
10 #include "prenv.h"
12 #include "nsIGlobalObject.h"
13 #include "nsRefPtrHashtable.h"
14 #include "nsString.h"
15 #include "mozilla/dom/GamepadHandle.h"
16 #include "mozilla/dom/GamepadManager.h"
17 #include "mozilla/dom/Gamepad.h"
18 #include "mozilla/dom/XRSession.h"
19 #include "mozilla/dom/XRInputSourceArray.h"
20 #include "mozilla/Preferences.h"
21 #include "mozilla/Unused.h"
22 #include "mozilla/StaticPrefs_dom.h"
23 #include "mozilla/Telemetry.h"
24 #include "mozilla/dom/WebXRBinding.h"
25 #include "nsServiceManagerUtils.h"
27 #ifdef XP_WIN
28 # include "../layers/d3d11/CompositorD3D11.h"
29 #endif
31 #include "VRDisplayClient.h"
32 #include "VRDisplayPresentation.h"
33 #include "VRManagerChild.h"
34 #include "VRLayerChild.h"
36 using namespace mozilla;
37 using namespace mozilla::gfx;
39 using mozilla::dom::GamepadHandle;
40 using mozilla::dom::GamepadHandleKind;
42 VRDisplayClient::VRDisplayClient(const VRDisplayInfo& aDisplayInfo)
43 : mDisplayInfo(aDisplayInfo),
44 bLastEventWasMounted(false),
45 bLastEventWasPresenting(false),
46 mPresentationCount(0),
47 mLastEventFrameId(0),
48 mLastPresentingGeneration(0),
49 mLastEventControllerState{},
50 // For now WebVR is default to prevent a VRDisplay restore bug in WebVR
51 // compatibility mode. See Bug 1630512
52 mAPIMode(VRAPIMode::WebVR) {
53 MOZ_COUNT_CTOR(VRDisplayClient);
56 VRDisplayClient::~VRDisplayClient() { MOZ_COUNT_DTOR(VRDisplayClient); }
58 void VRDisplayClient::UpdateDisplayInfo(const VRDisplayInfo& aDisplayInfo) {
59 mDisplayInfo = aDisplayInfo;
60 FireEvents();
63 already_AddRefed<VRDisplayPresentation> VRDisplayClient::BeginPresentation(
64 const nsTArray<mozilla::dom::VRLayer>& aLayers, uint32_t aGroup) {
65 PresentationCreated();
66 RefPtr<VRDisplayPresentation> presentation =
67 new VRDisplayPresentation(this, aLayers, aGroup);
68 return presentation.forget();
71 void VRDisplayClient::PresentationCreated() { ++mPresentationCount; }
73 void VRDisplayClient::PresentationDestroyed() { --mPresentationCount; }
75 void VRDisplayClient::SessionStarted(dom::XRSession* aSession) {
76 PresentationCreated();
77 MakePresentationGenerationCurrent();
78 mSessions.AppendElement(aSession);
80 void VRDisplayClient::SessionEnded(dom::XRSession* aSession) {
81 mSessions.RemoveElement(aSession);
82 PresentationDestroyed();
85 void VRDisplayClient::StartFrame() {
86 RefPtr<VRManagerChild> vm = VRManagerChild::Get();
87 vm->RunFrameRequestCallbacks();
89 nsTArray<RefPtr<dom::XRSession>> sessions;
90 sessions.AppendElements(mSessions);
91 for (auto session : sessions) {
92 session->StartFrame();
96 void VRDisplayClient::SetGroupMask(uint32_t aGroupMask) {
97 VRManagerChild* vm = VRManagerChild::Get();
98 vm->SendSetGroupMask(mDisplayInfo.mDisplayID, aGroupMask);
101 bool VRDisplayClient::IsPresentationGenerationCurrent() const {
102 if (mLastPresentingGeneration !=
103 mDisplayInfo.mDisplayState.presentingGeneration) {
104 return false;
107 return true;
110 void VRDisplayClient::MakePresentationGenerationCurrent() {
111 mLastPresentingGeneration = mDisplayInfo.mDisplayState.presentingGeneration;
114 gfx::VRAPIMode VRDisplayClient::GetXRAPIMode() const { return mAPIMode; }
116 void VRDisplayClient::SetXRAPIMode(gfx::VRAPIMode aMode) {
117 mAPIMode = aMode;
118 Telemetry::Accumulate(Telemetry::WEBXR_API_MODE,
119 static_cast<uint32_t>(mAPIMode));
122 void VRDisplayClient::FireEvents() {
123 RefPtr<VRManagerChild> vm = VRManagerChild::Get();
124 // Only fire these events for non-chrome VR sessions
125 bool isPresenting = (mDisplayInfo.mPresentingGroups & kVRGroupContent) != 0;
127 // Check if we need to trigger onVRDisplayPresentChange event
128 if (bLastEventWasPresenting != isPresenting) {
129 bLastEventWasPresenting = isPresenting;
130 vm->FireDOMVRDisplayPresentChangeEvent(mDisplayInfo.mDisplayID);
133 // Check if we need to trigger onvrdisplayactivate event
134 if (!bLastEventWasMounted && mDisplayInfo.mDisplayState.isMounted) {
135 bLastEventWasMounted = true;
136 if (StaticPrefs::dom_vr_autoactivate_enabled()) {
137 vm->FireDOMVRDisplayMountedEvent(mDisplayInfo.mDisplayID);
141 // Check if we need to trigger onvrdisplaydeactivate event
142 if (bLastEventWasMounted && !mDisplayInfo.mDisplayState.isMounted) {
143 bLastEventWasMounted = false;
144 if (StaticPrefs::dom_vr_autoactivate_enabled()) {
145 vm->FireDOMVRDisplayUnmountedEvent(mDisplayInfo.mDisplayID);
149 if (mLastPresentingGeneration !=
150 mDisplayInfo.mDisplayState.presentingGeneration) {
151 mLastPresentingGeneration = mDisplayInfo.mDisplayState.presentingGeneration;
152 vm->NotifyPresentationGenerationChanged(mDisplayInfo.mDisplayID);
155 // In WebXR spec, Gamepad instances returned by an XRInputSource's gamepad
156 // attribute MUST NOT be included in the array returned by
157 // navigator.getGamepads().
158 if (mAPIMode == VRAPIMode::WebVR) {
159 FireGamepadEvents();
161 // Update controller states into XRInputSourceArray.
162 for (auto& session : mSessions) {
163 dom::XRInputSourceArray* inputs = session->InputSources();
164 if (inputs) {
165 inputs->Update(session);
169 // Check if we need to trigger VRDisplay.requestAnimationFrame
170 if (mLastEventFrameId != mDisplayInfo.mFrameId) {
171 mLastEventFrameId = mDisplayInfo.mFrameId;
172 StartFrame();
176 void VRDisplayClient::GamepadMappingForWebVR(
177 VRControllerState& aControllerState) {
178 float triggerValue[kVRControllerMaxButtons];
179 memcpy(triggerValue, aControllerState.triggerValue,
180 sizeof(aControllerState.triggerValue));
181 const uint64_t buttonPressed = aControllerState.buttonPressed;
182 const uint64_t buttonTouched = aControllerState.buttonTouched;
184 auto SetTriggerValue = [&](uint64_t newSlot, uint64_t oldSlot) {
185 aControllerState.triggerValue[newSlot] = triggerValue[oldSlot];
187 auto ShiftButtonBitForNewSlot = [&](uint64_t newSlot, uint64_t oldSlot,
188 bool aIsTouch = false) {
189 if (aIsTouch) {
190 return ((buttonTouched & (1ULL << oldSlot)) != 0) * (1ULL << newSlot);
192 SetTriggerValue(newSlot, oldSlot);
193 return ((buttonPressed & (1ULL << oldSlot)) != 0) * (1ULL << newSlot);
196 switch (aControllerState.type) {
197 case VRControllerType::HTCVive:
198 aControllerState.buttonPressed =
199 ShiftButtonBitForNewSlot(1, 0) | ShiftButtonBitForNewSlot(2, 1) |
200 ShiftButtonBitForNewSlot(0, 2) | ShiftButtonBitForNewSlot(3, 4);
201 aControllerState.buttonTouched = ShiftButtonBitForNewSlot(0, 1, true) |
202 ShiftButtonBitForNewSlot(2, 1, true) |
203 ShiftButtonBitForNewSlot(0, 2, true) |
204 ShiftButtonBitForNewSlot(3, 4, true);
205 aControllerState.numButtons = 4;
206 aControllerState.numAxes = 2;
207 break;
208 case VRControllerType::MSMR:
209 aControllerState.buttonPressed =
210 ShiftButtonBitForNewSlot(1, 0) | ShiftButtonBitForNewSlot(2, 1) |
211 ShiftButtonBitForNewSlot(0, 2) | ShiftButtonBitForNewSlot(3, 3) |
212 ShiftButtonBitForNewSlot(4, 4);
213 aControllerState.buttonTouched = ShiftButtonBitForNewSlot(1, 0, true) |
214 ShiftButtonBitForNewSlot(2, 1, true) |
215 ShiftButtonBitForNewSlot(0, 2, true) |
216 ShiftButtonBitForNewSlot(3, 3, true) |
217 ShiftButtonBitForNewSlot(4, 4, true);
218 aControllerState.numButtons = 5;
219 aControllerState.numAxes = 4;
220 break;
221 case VRControllerType::HTCViveCosmos:
222 aControllerState.buttonPressed =
223 ShiftButtonBitForNewSlot(0, 0) | ShiftButtonBitForNewSlot(1, 1) |
224 ShiftButtonBitForNewSlot(4, 3) | ShiftButtonBitForNewSlot(2, 4) |
225 ShiftButtonBitForNewSlot(3, 5) | ShiftButtonBitForNewSlot(5, 6);
226 aControllerState.buttonTouched = ShiftButtonBitForNewSlot(0, 0, true) |
227 ShiftButtonBitForNewSlot(1, 1, true) |
228 ShiftButtonBitForNewSlot(4, 3, true) |
229 ShiftButtonBitForNewSlot(2, 4, true) |
230 ShiftButtonBitForNewSlot(3, 5, true) |
231 ShiftButtonBitForNewSlot(5, 6, true);
232 aControllerState.axisValue[0] = aControllerState.axisValue[2];
233 aControllerState.axisValue[1] = aControllerState.axisValue[3];
234 aControllerState.numButtons = 6;
235 aControllerState.numAxes = 2;
236 break;
237 case VRControllerType::HTCViveFocus:
238 aControllerState.buttonPressed =
239 ShiftButtonBitForNewSlot(0, 2) | ShiftButtonBitForNewSlot(1, 0);
240 aControllerState.buttonTouched = ShiftButtonBitForNewSlot(0, 2, true) |
241 ShiftButtonBitForNewSlot(1, 0, true);
242 aControllerState.numButtons = 2;
243 aControllerState.numAxes = 2;
244 break;
245 case VRControllerType::HTCViveFocusPlus: {
246 aControllerState.buttonPressed = ShiftButtonBitForNewSlot(0, 2) |
247 ShiftButtonBitForNewSlot(1, 0) |
248 ShiftButtonBitForNewSlot(2, 1);
249 aControllerState.buttonTouched = ShiftButtonBitForNewSlot(0, 2, true) |
250 ShiftButtonBitForNewSlot(1, 0, true) |
251 ShiftButtonBitForNewSlot(2, 1, true);
252 aControllerState.numButtons = 3;
253 aControllerState.numAxes = 2;
255 static Matrix4x4 focusPlusTransform;
256 Matrix4x4 originalMtx;
257 if (focusPlusTransform.IsIdentity()) {
258 focusPlusTransform.RotateX(-0.70f);
259 focusPlusTransform.PostTranslate(0.0f, 0.0f, 0.01f);
260 focusPlusTransform.Inverse();
262 gfx::Quaternion quat(aControllerState.pose.orientation[0],
263 aControllerState.pose.orientation[1],
264 aControllerState.pose.orientation[2],
265 aControllerState.pose.orientation[3]);
266 originalMtx.SetRotationFromQuaternion(quat);
267 originalMtx._41 = aControllerState.pose.position[0];
268 originalMtx._42 = aControllerState.pose.position[1];
269 originalMtx._43 = aControllerState.pose.position[2];
270 originalMtx = focusPlusTransform * originalMtx;
272 gfx::Point3D pos, scale;
273 originalMtx.Decompose(pos, quat, scale);
275 aControllerState.pose.position[0] = pos.x;
276 aControllerState.pose.position[1] = pos.y;
277 aControllerState.pose.position[2] = pos.z;
279 aControllerState.pose.orientation[0] = quat.x;
280 aControllerState.pose.orientation[1] = quat.y;
281 aControllerState.pose.orientation[2] = quat.z;
282 aControllerState.pose.orientation[3] = quat.w;
283 break;
285 case VRControllerType::OculusGo: {
286 aControllerState.buttonPressed =
287 ShiftButtonBitForNewSlot(0, 2) | ShiftButtonBitForNewSlot(1, 0);
288 aControllerState.buttonTouched = ShiftButtonBitForNewSlot(0, 2, true) |
289 ShiftButtonBitForNewSlot(1, 0, true);
290 aControllerState.numButtons = 2;
291 aControllerState.numAxes = 2;
293 static Matrix4x4 goTransform;
294 Matrix4x4 originalMtx;
296 if (goTransform.IsIdentity()) {
297 goTransform.RotateX(-0.60f);
298 goTransform.Inverse();
300 gfx::Quaternion quat(aControllerState.pose.orientation[0],
301 aControllerState.pose.orientation[1],
302 aControllerState.pose.orientation[2],
303 aControllerState.pose.orientation[3]);
304 originalMtx.SetRotationFromQuaternion(quat);
305 originalMtx._41 = aControllerState.pose.position[0];
306 originalMtx._42 = aControllerState.pose.position[1];
307 originalMtx._43 = aControllerState.pose.position[2];
308 originalMtx = goTransform * originalMtx;
310 gfx::Point3D pos, scale;
311 originalMtx.Decompose(pos, quat, scale);
313 aControllerState.pose.position[0] = pos.x;
314 aControllerState.pose.position[1] = pos.y;
315 aControllerState.pose.position[2] = pos.z;
317 aControllerState.pose.orientation[0] = quat.x;
318 aControllerState.pose.orientation[1] = quat.y;
319 aControllerState.pose.orientation[2] = quat.z;
320 aControllerState.pose.orientation[3] = quat.w;
321 break;
323 case VRControllerType::OculusTouch:
324 aControllerState.buttonPressed =
325 ShiftButtonBitForNewSlot(0, 3) | ShiftButtonBitForNewSlot(1, 0) |
326 ShiftButtonBitForNewSlot(2, 1) | ShiftButtonBitForNewSlot(3, 4) |
327 ShiftButtonBitForNewSlot(4, 5) | ShiftButtonBitForNewSlot(5, 6);
328 aControllerState.buttonTouched = ShiftButtonBitForNewSlot(0, 3, true) |
329 ShiftButtonBitForNewSlot(1, 0, true) |
330 ShiftButtonBitForNewSlot(2, 1, true) |
331 ShiftButtonBitForNewSlot(3, 4, true) |
332 ShiftButtonBitForNewSlot(4, 5, true) |
333 ShiftButtonBitForNewSlot(5, 6, true);
334 aControllerState.axisValue[0] = aControllerState.axisValue[2];
335 aControllerState.axisValue[1] = aControllerState.axisValue[3];
336 aControllerState.numButtons = 6;
337 aControllerState.numAxes = 2;
338 break;
339 case VRControllerType::OculusTouch2:
340 case VRControllerType::OculusTouch3: {
341 aControllerState.buttonPressed =
342 ShiftButtonBitForNewSlot(0, 3) | ShiftButtonBitForNewSlot(1, 0) |
343 ShiftButtonBitForNewSlot(2, 1) | ShiftButtonBitForNewSlot(3, 4) |
344 ShiftButtonBitForNewSlot(4, 5) | ShiftButtonBitForNewSlot(5, 6);
345 aControllerState.buttonTouched = ShiftButtonBitForNewSlot(0, 3, true) |
346 ShiftButtonBitForNewSlot(1, 0, true) |
347 ShiftButtonBitForNewSlot(2, 1, true) |
348 ShiftButtonBitForNewSlot(3, 4, true) |
349 ShiftButtonBitForNewSlot(4, 5, true) |
350 ShiftButtonBitForNewSlot(5, 6, true);
351 aControllerState.axisValue[0] = aControllerState.axisValue[2];
352 aControllerState.axisValue[1] = aControllerState.axisValue[3];
353 aControllerState.numButtons = 6;
354 aControllerState.numAxes = 2;
356 static Matrix4x4 touchTransform;
357 Matrix4x4 originalMtx;
359 if (touchTransform.IsIdentity()) {
360 touchTransform.RotateX(-0.77f);
361 touchTransform.PostTranslate(0.0f, 0.0f, -0.025f);
362 touchTransform.Inverse();
364 gfx::Quaternion quat(aControllerState.pose.orientation[0],
365 aControllerState.pose.orientation[1],
366 aControllerState.pose.orientation[2],
367 aControllerState.pose.orientation[3]);
368 originalMtx.SetRotationFromQuaternion(quat);
369 originalMtx._41 = aControllerState.pose.position[0];
370 originalMtx._42 = aControllerState.pose.position[1];
371 originalMtx._43 = aControllerState.pose.position[2];
372 originalMtx = touchTransform * originalMtx;
374 gfx::Point3D pos, scale;
375 originalMtx.Decompose(pos, quat, scale);
377 aControllerState.pose.position[0] = pos.x;
378 aControllerState.pose.position[1] = pos.y;
379 aControllerState.pose.position[2] = pos.z;
381 aControllerState.pose.orientation[0] = quat.x;
382 aControllerState.pose.orientation[1] = quat.y;
383 aControllerState.pose.orientation[2] = quat.z;
384 aControllerState.pose.orientation[3] = quat.w;
385 break;
387 case VRControllerType::ValveIndex:
388 aControllerState.buttonPressed =
389 ShiftButtonBitForNewSlot(1, 0) | ShiftButtonBitForNewSlot(2, 1) |
390 ShiftButtonBitForNewSlot(0, 2) | ShiftButtonBitForNewSlot(5, 3) |
391 ShiftButtonBitForNewSlot(3, 4) | ShiftButtonBitForNewSlot(4, 5) |
392 ShiftButtonBitForNewSlot(6, 6) | ShiftButtonBitForNewSlot(7, 7) |
393 ShiftButtonBitForNewSlot(8, 8) | ShiftButtonBitForNewSlot(9, 9);
394 aControllerState.buttonTouched = ShiftButtonBitForNewSlot(1, 0, true) |
395 ShiftButtonBitForNewSlot(2, 1, true) |
396 ShiftButtonBitForNewSlot(0, 2, true) |
397 ShiftButtonBitForNewSlot(5, 3, true) |
398 ShiftButtonBitForNewSlot(3, 4, true) |
399 ShiftButtonBitForNewSlot(4, 5, true) |
400 ShiftButtonBitForNewSlot(6, 6, true) |
401 ShiftButtonBitForNewSlot(7, 7, true) |
402 ShiftButtonBitForNewSlot(8, 8, true) |
403 ShiftButtonBitForNewSlot(9, 9, true);
404 aControllerState.numButtons = 10;
405 aControllerState.numAxes = 4;
406 break;
407 case VRControllerType::PicoGaze:
408 aControllerState.buttonPressed = ShiftButtonBitForNewSlot(0, 0);
409 aControllerState.buttonTouched = ShiftButtonBitForNewSlot(0, 0, true);
410 aControllerState.numButtons = 1;
411 aControllerState.numAxes = 0;
412 break;
413 case VRControllerType::PicoG2:
414 aControllerState.buttonPressed =
415 ShiftButtonBitForNewSlot(0, 2) | ShiftButtonBitForNewSlot(1, 0);
416 aControllerState.buttonTouched = ShiftButtonBitForNewSlot(0, 2, true) |
417 ShiftButtonBitForNewSlot(1, 0, true);
418 aControllerState.numButtons = 2;
419 aControllerState.numAxes = 2;
420 break;
421 case VRControllerType::PicoNeo2:
422 aControllerState.buttonPressed =
423 ShiftButtonBitForNewSlot(0, 3) | ShiftButtonBitForNewSlot(1, 0) |
424 ShiftButtonBitForNewSlot(2, 1) | ShiftButtonBitForNewSlot(3, 4) |
425 ShiftButtonBitForNewSlot(4, 5) | ShiftButtonBitForNewSlot(5, 6);
426 aControllerState.buttonTouched = ShiftButtonBitForNewSlot(0, 3, true) |
427 ShiftButtonBitForNewSlot(1, 0, true) |
428 ShiftButtonBitForNewSlot(2, 1, true) |
429 ShiftButtonBitForNewSlot(3, 4, true) |
430 ShiftButtonBitForNewSlot(4, 5, true) |
431 ShiftButtonBitForNewSlot(5, 6, true);
432 aControllerState.axisValue[0] = aControllerState.axisValue[2];
433 aControllerState.axisValue[1] = aControllerState.axisValue[3];
434 aControllerState.numButtons = 6;
435 aControllerState.numAxes = 2;
436 break;
437 default:
438 // Undefined controller types, we will keep its the same order.
439 break;
443 void VRDisplayClient::FireGamepadEvents() {
444 RefPtr<dom::GamepadManager> gamepadManager(dom::GamepadManager::GetService());
445 if (!gamepadManager) {
446 return;
448 for (int stateIndex = 0; stateIndex < kVRControllerMaxCount; stateIndex++) {
449 VRControllerState state = {}, lastState = {};
450 memcpy(&state, &mDisplayInfo.mControllerState[stateIndex],
451 sizeof(VRControllerState));
452 memcpy(&lastState, &mLastEventControllerState[stateIndex],
453 sizeof(VRControllerState));
454 GamepadMappingForWebVR(state);
455 GamepadMappingForWebVR(lastState);
457 uint32_t gamepadHandleValue =
458 mDisplayInfo.mDisplayID * kVRControllerMaxCount + stateIndex;
460 GamepadHandle gamepadHandle{gamepadHandleValue, GamepadHandleKind::VR};
462 bool bIsNew = false;
464 // Send events to notify that controllers are removed
465 if (state.controllerName[0] == '\0') {
466 // Controller is not present
467 if (lastState.controllerName[0] != '\0') {
468 // Controller has been removed
469 dom::GamepadRemoved info;
470 dom::GamepadChangeEventBody body(info);
471 dom::GamepadChangeEvent event(gamepadHandle, body);
472 gamepadManager->Update(event);
474 // Do not process any further events for removed controllers
475 continue;
478 // Send events to notify that new controllers are added
479 RefPtr<dom::Gamepad> existing = gamepadManager->GetGamepad(gamepadHandle);
480 // ControllerState in OpenVR action-based API gets delay to query btn and
481 // axis count. So, we need to check if they are more than zero.
482 if ((lastState.controllerName[0] == '\0' || !existing) &&
483 (state.numButtons > 0 || state.numAxes > 0)) {
484 dom::GamepadAdded info(NS_ConvertUTF8toUTF16(state.controllerName),
485 dom::GamepadMappingType::_empty, state.hand,
486 mDisplayInfo.mDisplayID, state.numButtons,
487 state.numAxes, state.numHaptics, 0, 0);
488 dom::GamepadChangeEventBody body(info);
489 dom::GamepadChangeEvent event(gamepadHandle, body);
490 gamepadManager->Update(event);
491 bIsNew = true;
494 // Send events for handedness changes
495 if (state.hand != lastState.hand) {
496 dom::GamepadHandInformation info(state.hand);
497 dom::GamepadChangeEventBody body(info);
498 dom::GamepadChangeEvent event(gamepadHandle, body);
499 gamepadManager->Update(event);
502 // Send events for axis value changes
503 for (uint32_t axisIndex = 0; axisIndex < state.numAxes; axisIndex++) {
504 if (state.axisValue[axisIndex] != lastState.axisValue[axisIndex]) {
505 dom::GamepadAxisInformation info(axisIndex, state.axisValue[axisIndex]);
506 dom::GamepadChangeEventBody body(info);
507 dom::GamepadChangeEvent event(gamepadHandle, body);
508 gamepadManager->Update(event);
512 // Send events for trigger, touch, and button value changes
513 if (!bIsNew) {
514 // When a new controller is added, we do not emit button events for
515 // the initial state of the inputs.
516 for (uint32_t buttonIndex = 0; buttonIndex < state.numButtons;
517 buttonIndex++) {
518 bool bPressed = (state.buttonPressed & (1ULL << buttonIndex)) != 0;
519 bool bTouched = (state.buttonTouched & (1ULL << buttonIndex)) != 0;
520 bool bLastPressed =
521 (lastState.buttonPressed & (1ULL << buttonIndex)) != 0;
522 bool bLastTouched =
523 (lastState.buttonTouched & (1ULL << buttonIndex)) != 0;
525 if (state.triggerValue[buttonIndex] !=
526 lastState.triggerValue[buttonIndex] ||
527 bPressed != bLastPressed || bTouched != bLastTouched) {
528 dom::GamepadButtonInformation info(
529 buttonIndex, state.triggerValue[buttonIndex], bPressed, bTouched);
530 dom::GamepadChangeEventBody body(info);
531 dom::GamepadChangeEvent event(gamepadHandle, body);
532 gamepadManager->Update(event);
537 // Send events for pose changes
538 // Note that VRPose is asserted to be a POD type so memcmp is safe
539 if (state.flags != lastState.flags ||
540 state.isPositionValid != lastState.isPositionValid ||
541 state.isOrientationValid != lastState.isOrientationValid ||
542 memcmp(&state.pose, &lastState.pose, sizeof(VRPose)) != 0) {
543 // Convert pose to GamepadPoseState
544 dom::GamepadPoseState poseState;
545 poseState.Clear();
546 poseState.flags = state.flags;
548 // Orientation values
549 poseState.isOrientationValid = state.isOrientationValid;
550 poseState.orientation[0] = state.pose.orientation[0];
551 poseState.orientation[1] = state.pose.orientation[1];
552 poseState.orientation[2] = state.pose.orientation[2];
553 poseState.orientation[3] = state.pose.orientation[3];
554 poseState.angularVelocity[0] = state.pose.angularVelocity[0];
555 poseState.angularVelocity[1] = state.pose.angularVelocity[1];
556 poseState.angularVelocity[2] = state.pose.angularVelocity[2];
557 poseState.angularAcceleration[0] = state.pose.angularAcceleration[0];
558 poseState.angularAcceleration[1] = state.pose.angularAcceleration[1];
559 poseState.angularAcceleration[2] = state.pose.angularAcceleration[2];
561 // Position values
562 poseState.isPositionValid = state.isPositionValid;
563 poseState.position[0] = state.pose.position[0];
564 poseState.position[1] = state.pose.position[1];
565 poseState.position[2] = state.pose.position[2];
566 poseState.linearVelocity[0] = state.pose.linearVelocity[0];
567 poseState.linearVelocity[1] = state.pose.linearVelocity[1];
568 poseState.linearVelocity[2] = state.pose.linearVelocity[2];
569 poseState.linearAcceleration[0] = state.pose.linearAcceleration[0];
570 poseState.linearAcceleration[1] = state.pose.linearAcceleration[1];
571 poseState.linearAcceleration[2] = state.pose.linearAcceleration[2];
573 // Send the event
574 dom::GamepadPoseInformation info(poseState);
575 dom::GamepadChangeEventBody body(info);
576 dom::GamepadChangeEvent event(gamepadHandle, body);
577 gamepadManager->Update(event);
581 // Note that VRControllerState is asserted to be a POD type and memcpy is
582 // safe.
583 memcpy(mLastEventControllerState, mDisplayInfo.mControllerState,
584 sizeof(VRControllerState) * kVRControllerMaxCount);
587 const VRHMDSensorState& VRDisplayClient::GetSensorState() const {
588 return mDisplayInfo.GetSensorState();
591 bool VRDisplayClient::GetIsConnected() const {
592 return mDisplayInfo.GetIsConnected();
595 bool VRDisplayClient::IsPresenting() {
596 return mDisplayInfo.mPresentingGroups != 0;
599 void VRDisplayClient::NotifyDisconnected() {
600 mDisplayInfo.mDisplayState.isConnected = false;
603 void VRDisplayClient::UpdateSubmitFrameResult(
604 const VRSubmitFrameResultInfo& aResult) {
605 mSubmitFrameResult = aResult;
608 void VRDisplayClient::GetSubmitFrameResult(VRSubmitFrameResultInfo& aResult) {
609 aResult = mSubmitFrameResult;
612 void VRDisplayClient::StartVRNavigation() {
614 * A VR-to-VR site navigation has started, notify VRManager
615 * so we don't drop out of VR during the transition
617 VRManagerChild* vm = VRManagerChild::Get();
618 vm->SendStartVRNavigation(mDisplayInfo.mDisplayID);
621 void VRDisplayClient::StopVRNavigation(const TimeDuration& aTimeout) {
623 * A VR-to-VR site navigation has ended and the new site
624 * has received a vrdisplayactivate event.
625 * Don't actually consider the navigation transition over
626 * until aTimeout has elapsed.
627 * This may be called multiple times, in which case the timeout
628 * should be reset to aTimeout.
629 * When aTimeout is TimeDuration(0), we should consider the
630 * transition immediately ended.
632 VRManagerChild* vm = VRManagerChild::Get();
633 vm->SendStopVRNavigation(mDisplayInfo.mDisplayID, aTimeout);
636 bool VRDisplayClient::IsReferenceSpaceTypeSupported(
637 dom::XRReferenceSpaceType aType) const {
639 * https://immersive-web.github.io/webxr/#reference-space-is-supported
641 * We do not yet support local or local-floor for inline sessions.
642 * This could be expanded if we later support WebXR for inline-ar
643 * sessions on Firefox Fenix.
645 * We do not yet support unbounded reference spaces.
647 switch (aType) {
648 case dom::XRReferenceSpaceType::Viewer:
649 // Viewer is always supported, for both inline and immersive sessions
650 return true;
651 case dom::XRReferenceSpaceType::Local:
652 case dom::XRReferenceSpaceType::Local_floor:
653 // Local and Local_Floor are always supported for immersive sessions
654 return bool(mDisplayInfo.GetCapabilities() &
655 (VRDisplayCapabilityFlags::Cap_ImmersiveVR |
656 VRDisplayCapabilityFlags::Cap_ImmersiveAR));
657 case dom::XRReferenceSpaceType::Bounded_floor:
658 return bool(mDisplayInfo.GetCapabilities() &
659 VRDisplayCapabilityFlags::Cap_StageParameters);
660 default:
661 NS_WARNING(
662 "Unknown XRReferenceSpaceType passed to "
663 "VRDisplayClient::IsReferenceSpaceTypeSupported");
664 return false;