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/. */
12 #include "nsIGlobalObject.h"
13 #include "nsRefPtrHashtable.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"
28 # include "../layers/d3d11/CompositorD3D11.h"
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),
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
;
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
) {
110 void VRDisplayClient::MakePresentationGenerationCurrent() {
111 mLastPresentingGeneration
= mDisplayInfo
.mDisplayState
.presentingGeneration
;
114 gfx::VRAPIMode
VRDisplayClient::GetXRAPIMode() const { return mAPIMode
; }
116 void VRDisplayClient::SetXRAPIMode(gfx::VRAPIMode 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
) {
161 // Update controller states into XRInputSourceArray.
162 for (auto& session
: mSessions
) {
163 dom::XRInputSourceArray
* inputs
= session
->InputSources();
165 inputs
->Update(session
);
169 // Check if we need to trigger VRDisplay.requestAnimationFrame
170 if (mLastEventFrameId
!= mDisplayInfo
.mFrameId
) {
171 mLastEventFrameId
= mDisplayInfo
.mFrameId
;
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) {
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;
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;
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;
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;
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
;
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
;
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;
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
;
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;
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;
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;
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;
438 // Undefined controller types, we will keep its the same order.
443 void VRDisplayClient::FireGamepadEvents() {
444 RefPtr
<dom::GamepadManager
> gamepadManager(dom::GamepadManager::GetService());
445 if (!gamepadManager
) {
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
};
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
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
);
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
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
;
518 bool bPressed
= (state
.buttonPressed
& (1ULL << buttonIndex
)) != 0;
519 bool bTouched
= (state
.buttonTouched
& (1ULL << buttonIndex
)) != 0;
521 (lastState
.buttonPressed
& (1ULL << buttonIndex
)) != 0;
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
;
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];
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];
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
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.
648 case dom::XRReferenceSpaceType::Viewer
:
649 // Viewer is always supported, for both inline and immersive sessions
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
);
662 "Unknown XRReferenceSpaceType passed to "
663 "VRDisplayClient::IsReferenceSpaceTypeSupported");