Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/vr/VRDisplayClient.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 <math.h>
8
9
#include "prlink.h"
10
#include "prenv.h"
11
#include "gfxPrefs.h"
12
#include "nsIGlobalObject.h"
13
#include "nsRefPtrHashtable.h"
14
#include "nsString.h"
15
#include "mozilla/dom/GamepadManager.h"
16
#include "mozilla/dom/Gamepad.h"
17
#include "mozilla/Preferences.h"
18
#include "mozilla/Unused.h"
19
#include "nsServiceManagerUtils.h"
20
#include "nsIScreenManager.h"
21
22
#ifdef XP_WIN
23
#include "../layers/d3d11/CompositorD3D11.h"
24
#endif
25
26
#include "VRDisplayClient.h"
27
#include "VRDisplayPresentation.h"
28
#include "VRManagerChild.h"
29
#include "VRLayerChild.h"
30
31
using namespace mozilla;
32
using namespace mozilla::gfx;
33
34
VRDisplayClient::VRDisplayClient(const VRDisplayInfo& aDisplayInfo)
35
  : mDisplayInfo(aDisplayInfo)
36
  , bLastEventWasMounted(false)
37
  , bLastEventWasPresenting(false)
38
  , mPresentationCount(0)
39
  , mLastEventFrameId(0)
40
  , mLastPresentingGeneration(0)
41
  , mLastEventControllerState{}
42
0
{
43
0
  MOZ_COUNT_CTOR(VRDisplayClient);
44
0
}
45
46
0
VRDisplayClient::~VRDisplayClient() {
47
0
  MOZ_COUNT_DTOR(VRDisplayClient);
48
0
}
49
50
void
51
VRDisplayClient::UpdateDisplayInfo(const VRDisplayInfo& aDisplayInfo)
52
0
{
53
0
  mDisplayInfo = aDisplayInfo;
54
0
  FireEvents();
55
0
}
56
57
already_AddRefed<VRDisplayPresentation>
58
VRDisplayClient::BeginPresentation(const nsTArray<mozilla::dom::VRLayer>& aLayers,
59
                                   uint32_t aGroup)
60
0
{
61
0
  ++mPresentationCount;
62
0
  RefPtr<VRDisplayPresentation> presentation = new VRDisplayPresentation(this, aLayers, aGroup);
63
0
  return presentation.forget();
64
0
}
65
66
void
67
VRDisplayClient::PresentationDestroyed()
68
0
{
69
0
  --mPresentationCount;
70
0
}
71
72
void
73
VRDisplayClient::ZeroSensor()
74
0
{
75
0
  VRManagerChild *vm = VRManagerChild::Get();
76
0
  vm->SendResetSensor(mDisplayInfo.mDisplayID);
77
0
}
78
79
void
80
VRDisplayClient::SetGroupMask(uint32_t aGroupMask)
81
0
{
82
0
  VRManagerChild *vm = VRManagerChild::Get();
83
0
  vm->SendSetGroupMask(mDisplayInfo.mDisplayID, aGroupMask);
84
0
}
85
86
bool
87
VRDisplayClient::IsPresentationGenerationCurrent() const
88
0
{
89
0
  if (mLastPresentingGeneration != mDisplayInfo.mDisplayState.mPresentingGeneration) {
90
0
    return false;
91
0
  }
92
0
93
0
  return true;
94
0
}
95
96
void
97
VRDisplayClient::MakePresentationGenerationCurrent()
98
0
{
99
0
  mLastPresentingGeneration = mDisplayInfo.mDisplayState.mPresentingGeneration;
100
0
}
101
102
void
103
VRDisplayClient::FireEvents()
104
0
{
105
0
  VRManagerChild *vm = VRManagerChild::Get();
106
0
  // Only fire these events for non-chrome VR sessions
107
0
  bool isPresenting = (mDisplayInfo.mPresentingGroups & kVRGroupContent) != 0;
108
0
109
0
  // Check if we need to trigger onVRDisplayPresentChange event
110
0
  if (bLastEventWasPresenting != isPresenting) {
111
0
    bLastEventWasPresenting = isPresenting;
112
0
    vm->FireDOMVRDisplayPresentChangeEvent(mDisplayInfo.mDisplayID);
113
0
  }
114
0
115
0
  // Check if we need to trigger onvrdisplayactivate event
116
0
  if (!bLastEventWasMounted && mDisplayInfo.mDisplayState.mIsMounted) {
117
0
    bLastEventWasMounted = true;
118
0
    if (gfxPrefs::VRAutoActivateEnabled()) {
119
0
      vm->FireDOMVRDisplayMountedEvent(mDisplayInfo.mDisplayID);
120
0
    }
121
0
  }
122
0
123
0
  // Check if we need to trigger onvrdisplaydeactivate event
124
0
  if (bLastEventWasMounted && !mDisplayInfo.mDisplayState.mIsMounted) {
125
0
    bLastEventWasMounted = false;
126
0
    if (gfxPrefs::VRAutoActivateEnabled()) {
127
0
      vm->FireDOMVRDisplayUnmountedEvent(mDisplayInfo.mDisplayID);
128
0
    }
129
0
  }
130
0
131
0
  if (mLastPresentingGeneration != mDisplayInfo.mDisplayState.mPresentingGeneration) {
132
0
    mLastPresentingGeneration = mDisplayInfo.mDisplayState.mPresentingGeneration;
133
0
    vm->NotifyPresentationGenerationChanged(mDisplayInfo.mDisplayID);
134
0
  }
135
0
136
0
  // Check if we need to trigger VRDisplay.requestAnimationFrame
137
0
  if (mLastEventFrameId != mDisplayInfo.mFrameId) {
138
0
    mLastEventFrameId = mDisplayInfo.mFrameId;
139
0
    vm->RunFrameRequestCallbacks();
140
0
  }
141
0
142
0
  FireGamepadEvents();
143
0
}
144
145
void
146
VRDisplayClient::FireGamepadEvents()
147
0
{
148
0
  RefPtr<dom::GamepadManager> gamepadManager(dom::GamepadManager::GetService());
149
0
  if (!gamepadManager) {
150
0
    return;
151
0
  }
152
0
  for (int stateIndex=0; stateIndex < kVRControllerMaxCount; stateIndex++) {
153
0
    const VRControllerState& state = mDisplayInfo.mControllerState[stateIndex];
154
0
    const VRControllerState& lastState = mLastEventControllerState[stateIndex];
155
0
    uint32_t gamepadId = mDisplayInfo.mDisplayID * kVRControllerMaxCount + stateIndex;
156
0
    bool bIsNew = false;
157
0
158
0
    // Send events to notify that controllers are removed
159
0
    if (state.controllerName[0] == '\0') {
160
0
      // Controller is not present
161
0
      if (lastState.controllerName[0] != '\0') {
162
0
        // Controller has been removed
163
0
        dom::GamepadRemoved info;
164
0
        dom::GamepadChangeEventBody body(info);
165
0
        dom::GamepadChangeEvent event(gamepadId, dom::GamepadServiceType::VR, body);
166
0
        gamepadManager->Update(event);
167
0
      }
168
0
      // Do not process any further events for removed controllers
169
0
      continue;
170
0
    }
171
0
172
0
    // Send events to notify that new controllers are added
173
0
    RefPtr<dom::Gamepad> existing = gamepadManager->GetGamepad(gamepadId, dom::GamepadServiceType::VR);
174
0
    if (lastState.controllerName[0] == '\0' || !existing) {
175
0
      dom::GamepadAdded info(NS_ConvertUTF8toUTF16(state.controllerName),
176
0
                             dom::GamepadMappingType::_empty,
177
0
                             state.hand,
178
0
                             mDisplayInfo.mDisplayID,
179
0
                             state.numButtons,
180
0
                             state.numAxes,
181
0
                             state.numHaptics);
182
0
      dom::GamepadChangeEventBody body(info);
183
0
      dom::GamepadChangeEvent event(gamepadId, dom::GamepadServiceType::VR, body);
184
0
      gamepadManager->Update(event);
185
0
      bIsNew = true;
186
0
    }
187
0
188
0
    // Send events for handedness changes
189
0
    if (state.hand != lastState.hand) {
190
0
      dom::GamepadHandInformation info(state.hand);
191
0
      dom::GamepadChangeEventBody body(info);
192
0
      dom::GamepadChangeEvent event(gamepadId, dom::GamepadServiceType::VR, body);
193
0
      gamepadManager->Update(event);
194
0
    }
195
0
196
0
    // Send events for axis value changes
197
0
    for (uint32_t axisIndex = 0; axisIndex < state.numAxes; axisIndex++) {
198
0
      if (state.axisValue[axisIndex] != lastState.axisValue[axisIndex]) {
199
0
        dom::GamepadAxisInformation info(axisIndex, state.axisValue[axisIndex]);
200
0
        dom::GamepadChangeEventBody body(info);
201
0
        dom::GamepadChangeEvent event(gamepadId, dom::GamepadServiceType::VR, body);
202
0
        gamepadManager->Update(event);
203
0
      }
204
0
    }
205
0
206
0
    // Send events for trigger, touch, and button value changes
207
0
    if (!bIsNew) {
208
0
      // When a new controller is added, we do not emit button events for
209
0
      // the initial state of the inputs.
210
0
      for (uint32_t buttonIndex = 0; buttonIndex < state.numButtons; buttonIndex++) {
211
0
        bool bPressed = (state.buttonPressed & (1ULL << buttonIndex)) != 0;
212
0
        bool bTouched = (state.buttonTouched & (1ULL << buttonIndex)) != 0;
213
0
        bool bLastPressed = (lastState.buttonPressed & (1ULL << buttonIndex)) != 0;
214
0
        bool bLastTouched = (lastState.buttonTouched & (1ULL << buttonIndex)) != 0;
215
0
216
0
        if (state.triggerValue[buttonIndex] != lastState.triggerValue[buttonIndex] ||
217
0
            bPressed != bLastPressed ||
218
0
            bTouched != bLastTouched) {
219
0
          dom::GamepadButtonInformation info(buttonIndex, state.triggerValue[buttonIndex], bPressed, bTouched);
220
0
          dom::GamepadChangeEventBody body(info);
221
0
          dom::GamepadChangeEvent event(gamepadId, dom::GamepadServiceType::VR, body);
222
0
          gamepadManager->Update(event);
223
0
        }
224
0
      }
225
0
    }
226
0
227
0
    // Send events for pose changes
228
0
    // Note that VRPose is asserted to be a POD type so memcmp is safe
229
0
    if (state.flags != lastState.flags ||
230
0
        state.isPositionValid != lastState.isPositionValid ||
231
0
        state.isOrientationValid != lastState.isOrientationValid ||
232
0
        memcmp(&state.pose, &lastState.pose, sizeof(VRPose)) != 0) {
233
0
234
0
      // Convert pose to GamepadPoseState
235
0
      dom::GamepadPoseState poseState;
236
0
      poseState.Clear();
237
0
      poseState.flags = state.flags;
238
0
239
0
      // Orientation values
240
0
      poseState.isOrientationValid = state.isOrientationValid;
241
0
      poseState.orientation[0] = state.pose.orientation[0];
242
0
      poseState.orientation[1] = state.pose.orientation[1];
243
0
      poseState.orientation[2] = state.pose.orientation[2];
244
0
      poseState.orientation[3] = state.pose.orientation[3];
245
0
      poseState.angularVelocity[0] = state.pose.angularVelocity[0];
246
0
      poseState.angularVelocity[1] = state.pose.angularVelocity[1];
247
0
      poseState.angularVelocity[2] = state.pose.angularVelocity[2];
248
0
      poseState.angularAcceleration[0] = state.pose.angularAcceleration[0];
249
0
      poseState.angularAcceleration[1] = state.pose.angularAcceleration[1];
250
0
      poseState.angularAcceleration[2] = state.pose.angularAcceleration[2];
251
0
252
0
      // Position values
253
0
      poseState.isPositionValid = state.isPositionValid;
254
0
      poseState.position[0] = state.pose.position[0];
255
0
      poseState.position[1] = state.pose.position[1];
256
0
      poseState.position[2] = state.pose.position[2];
257
0
      poseState.linearVelocity[0] = state.pose.linearVelocity[0];
258
0
      poseState.linearVelocity[1] = state.pose.linearVelocity[1];
259
0
      poseState.linearVelocity[2] = state.pose.linearVelocity[2];
260
0
      poseState.linearAcceleration[0] = state.pose.linearAcceleration[0];
261
0
      poseState.linearAcceleration[1] = state.pose.linearAcceleration[1];
262
0
      poseState.linearAcceleration[2] = state.pose.linearAcceleration[2];
263
0
264
0
      // Send the event
265
0
      dom::GamepadPoseInformation info(poseState);
266
0
      dom::GamepadChangeEventBody body(info);
267
0
      dom::GamepadChangeEvent event(gamepadId, dom::GamepadServiceType::VR, body);
268
0
      gamepadManager->Update(event);
269
0
    }
270
0
  }
271
0
272
0
  // Note that VRControllerState is asserted to be a POD type and memcpy is safe.
273
0
  memcpy(mLastEventControllerState,
274
0
         mDisplayInfo.mControllerState,
275
0
         sizeof(VRControllerState) * kVRControllerMaxCount);
276
0
}
277
278
VRHMDSensorState
279
VRDisplayClient::GetSensorState()
280
0
{
281
0
  return mDisplayInfo.GetSensorState();
282
0
}
283
284
bool
285
VRDisplayClient::GetIsConnected() const
286
0
{
287
0
  return mDisplayInfo.GetIsConnected();
288
0
}
289
290
void
291
VRDisplayClient::NotifyDisconnected()
292
0
{
293
0
  mDisplayInfo.mDisplayState.mIsConnected = false;
294
0
}
295
296
void
297
VRDisplayClient::UpdateSubmitFrameResult(const VRSubmitFrameResultInfo& aResult)
298
0
{
299
0
  mSubmitFrameResult = aResult;
300
0
}
301
302
void
303
VRDisplayClient::GetSubmitFrameResult(VRSubmitFrameResultInfo& aResult)
304
0
{
305
0
  aResult = mSubmitFrameResult;
306
0
}
307
308
void
309
VRDisplayClient::StartVRNavigation()
310
0
{
311
0
  /**
312
0
   * A VR-to-VR site navigation has started, notify VRManager
313
0
   * so we don't drop out of VR during the transition
314
0
   */
315
0
  VRManagerChild *vm = VRManagerChild::Get();
316
0
  vm->SendStartVRNavigation(mDisplayInfo.mDisplayID);
317
0
}
318
319
void
320
VRDisplayClient::StopVRNavigation(const TimeDuration& aTimeout)
321
0
{
322
0
  /**
323
0
   * A VR-to-VR site navigation has ended and the new site
324
0
   * has received a vrdisplayactivate event.
325
0
   * Don't actually consider the navigation transition over
326
0
   * until aTimeout has elapsed.
327
0
   * This may be called multiple times, in which case the timeout
328
0
   * should be reset to aTimeout.
329
0
   * When aTimeout is TimeDuration(0), we should consider the
330
0
   * transition immediately ended.
331
0
   */
332
0
  VRManagerChild *vm = VRManagerChild::Get();
333
0
  vm->SendStopVRNavigation(mDisplayInfo.mDisplayID, aTimeout);
334
0
}