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