Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/vr/gfxVRExternal.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 "mozilla/Preferences.h"
13
14
#include "mozilla/gfx/Quaternion.h"
15
16
#ifdef XP_WIN
17
#include "CompositorD3D11.h"
18
#include "TextureD3D11.h"
19
static const char* kShmemName = "moz.gecko.vr_ext.0.0.1";
20
#elif defined(XP_MACOSX)
21
#include "mozilla/gfx/MacIOSurface.h"
22
#include <sys/mman.h>
23
#include <sys/stat.h>        /* For mode constants */
24
#include <fcntl.h>           /* For O_* constants */
25
#include <errno.h>
26
static const char* kShmemName = "/moz.gecko.vr_ext.0.0.1";
27
#elif defined(MOZ_WIDGET_ANDROID)
28
#include <string.h>
29
#include <pthread.h>
30
#include "GeckoVRManager.h"
31
#endif // defined(MOZ_WIDGET_ANDROID)
32
33
#include "gfxVRExternal.h"
34
#include "VRManagerParent.h"
35
#include "VRManager.h"
36
#include "VRThread.h"
37
38
#include "nsServiceManagerUtils.h"
39
#include "nsIScreenManager.h"
40
41
#include "mozilla/dom/GamepadEventTypes.h"
42
#include "mozilla/dom/GamepadBinding.h"
43
#include "mozilla/Telemetry.h"
44
45
#ifndef M_PI
46
# define M_PI 3.14159265358979323846
47
#endif
48
49
using namespace mozilla;
50
using namespace mozilla::gfx;
51
using namespace mozilla::gfx::impl;
52
using namespace mozilla::layers;
53
using namespace mozilla::dom;
54
55
VRDisplayExternal::VRDisplayExternal(const VRDisplayState& aDisplayState)
56
  : VRDisplayHost(VRDeviceType::External)
57
  , mBrowserState{}
58
  , mLastSensorState{}
59
0
{
60
0
  MOZ_COUNT_CTOR_INHERITED(VRDisplayExternal, VRDisplayHost);
61
0
  mDisplayInfo.mDisplayState = aDisplayState;
62
0
63
0
  // default to an identity quaternion
64
0
  mLastSensorState.pose.orientation[3] = 1.0f;
65
0
}
66
67
VRDisplayExternal::~VRDisplayExternal()
68
0
{
69
0
  Destroy();
70
0
  MOZ_COUNT_DTOR_INHERITED(VRDisplayExternal, VRDisplayHost);
71
0
}
72
73
void
74
VRDisplayExternal::Destroy()
75
0
{
76
0
  StopPresentation();
77
0
}
78
79
void
80
VRDisplayExternal::ZeroSensor()
81
0
{
82
0
}
83
84
void
85
VRDisplayExternal::Refresh()
86
0
{
87
0
88
0
  if (!mVRNavigationTransitionEnd.IsNull() &&
89
0
      TimeStamp::Now() > mVRNavigationTransitionEnd) {
90
0
    mBrowserState.navigationTransitionActive = false;
91
0
  }
92
0
93
0
  PullState();
94
0
  PushState();
95
0
}
96
97
VRHMDSensorState
98
VRDisplayExternal::GetSensorState()
99
0
{
100
0
  return mLastSensorState;
101
0
}
102
103
void
104
VRDisplayExternal::StartPresentation()
105
0
{
106
0
  if (mBrowserState.presentationActive) {
107
0
    return;
108
0
  }
109
0
  mTelemetry.Clear();
110
0
  mTelemetry.mPresentationStart = TimeStamp::Now();
111
0
112
0
  // Indicate that we are ready to start immersive mode
113
0
  mBrowserState.presentationActive = true;
114
0
  mBrowserState.layerState[0].type = VRLayerType::LayerType_Stereo_Immersive;
115
0
  PushState();
116
0
117
#if defined(MOZ_WIDGET_ANDROID)
118
  mLastSubmittedFrameId = 0;
119
  mLastStartedFrame = 0;
120
  /**
121
   * Android compositor is paused when presentation starts. That causes VRManager::NotifyVsync() not to be called.
122
   * We post a VRTask to call VRManager::NotifyVsync() while the compositor is paused on Android.
123
   * VRManager::NotifyVsync() should be called constinuosly while the compositor is paused because Gecko WebVR Architecture
124
   * relies on that to act as a "watchdog" in order to avoid render loop stalls and recover from SubmitFrame call timeouts.
125
   */
126
  PostVRTask();
127
#endif
128
  // TODO - Implement telemetry:
129
0
130
0
  // mTelemetry.mLastDroppedFrameCount = stats.m_nNumReprojectedFrames;
131
0
}
132
133
#if defined(MOZ_WIDGET_ANDROID)
134
void
135
VRDisplayExternal::PostVRTask() {
136
  MessageLoop * vrLoop = VRListenerThreadHolder::Loop();
137
  if (!vrLoop || !mBrowserState.presentationActive) {
138
    return;
139
  }
140
  RefPtr<Runnable> task = NewRunnableMethod(
141
    "VRDisplayExternal::RunVRTask",
142
    this,
143
    &VRDisplayExternal::RunVRTask);
144
  VRListenerThreadHolder::Loop()->PostDelayedTask(task.forget(), 50);
145
}
146
147
void
148
VRDisplayExternal::RunVRTask() {
149
  if (mBrowserState.presentationActive) {
150
    VRManager *vm = VRManager::Get();
151
    vm->NotifyVsync(TimeStamp::Now());
152
    PostVRTask();
153
  }
154
}
155
156
#endif // defined(MOZ_WIDGET_ANDROID)
157
158
void
159
VRDisplayExternal::StopPresentation()
160
0
{
161
0
  if (!mBrowserState.presentationActive) {
162
0
    return;
163
0
  }
164
0
165
0
  // Indicate that we have stopped immersive mode
166
0
  mBrowserState.presentationActive = false;
167
0
  memset(mBrowserState.layerState, 0, sizeof(VRLayerState) * mozilla::ArrayLength(mBrowserState.layerState));
168
0
169
0
  PushState(true);
170
0
171
0
  // TODO - Implement telemetry:
172
0
173
0
/*
174
0
  const TimeDuration duration = TimeStamp::Now() - mTelemetry.mPresentationStart;
175
0
  Telemetry::Accumulate(Telemetry::WEBVR_USERS_VIEW_IN, 2);
176
0
  Telemetry::Accumulate(Telemetry::WEBVR_TIME_SPENT_VIEWING_IN_OPENVR,
177
0
                        duration.ToMilliseconds());
178
0
179
0
  ::vr::Compositor_CumulativeStats stats;
180
0
  mVRCompositor->GetCumulativeStats(&stats, sizeof(::vr::Compositor_CumulativeStats));
181
0
  const uint32_t droppedFramesPerSec = (stats.m_nNumReprojectedFrames -
182
0
                                        mTelemetry.mLastDroppedFrameCount) / duration.ToSeconds();
183
0
  Telemetry::Accumulate(Telemetry::WEBVR_DROPPED_FRAMES_IN_OPENVR, droppedFramesPerSec);
184
0
*/
185
0
}
186
187
void
188
VRDisplayExternal::StartVRNavigation()
189
0
{
190
0
  mBrowserState.navigationTransitionActive = true;
191
0
  mVRNavigationTransitionEnd = TimeStamp();
192
0
  PushState();
193
0
}
194
195
void
196
VRDisplayExternal::StopVRNavigation(const TimeDuration& aTimeout)
197
0
{
198
0
  if (aTimeout.ToMilliseconds() <= 0) {
199
0
    mBrowserState.navigationTransitionActive = false;
200
0
    mVRNavigationTransitionEnd = TimeStamp();
201
0
    PushState();
202
0
  }
203
0
  mVRNavigationTransitionEnd = TimeStamp::Now() + aTimeout;
204
0
}
205
206
bool
207
VRDisplayExternal::PopulateLayerTexture(const layers::SurfaceDescriptor& aTexture,
208
                                        VRLayerTextureType* aTextureType,
209
                                        VRLayerTextureHandle* aTextureHandle)
210
0
{
211
0
  switch (aTexture.type()) {
212
#if defined(XP_WIN)
213
    case SurfaceDescriptor::TSurfaceDescriptorD3D10: {
214
      const SurfaceDescriptorD3D10& surf = aTexture.get_SurfaceDescriptorD3D10();
215
      *aTextureType = VRLayerTextureType::LayerTextureType_D3D10SurfaceDescriptor;
216
      *aTextureHandle = (void *)surf.handle();
217
      return true;
218
    }
219
#elif defined(XP_MACOSX)
220
    case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface: {
221
      const auto& desc = aTexture.get_SurfaceDescriptorMacIOSurface();
222
      RefPtr<MacIOSurface> surf = MacIOSurface::LookupSurface(desc.surfaceId(),
223
                                                              desc.scaleFactor(),
224
                                                              !desc.isOpaque());
225
      if (!surf) {
226
        NS_WARNING("VRDisplayHost::SubmitFrame failed to get a MacIOSurface");
227
        return false;
228
      }
229
      *aTextureType = VRLayerTextureType::LayerTextureType_MacIOSurface;
230
      *aTextureHandle = (void *)surf->GetIOSurfacePtr();
231
      return true;
232
    }
233
#elif defined(MOZ_WIDGET_ANDROID)
234
    case SurfaceDescriptor::TSurfaceTextureDescriptor: {
235
      const SurfaceTextureDescriptor& desc = aTexture.get_SurfaceTextureDescriptor();
236
      java::GeckoSurfaceTexture::LocalRef surfaceTexture = java::GeckoSurfaceTexture::Lookup(desc.handle());
237
      if (!surfaceTexture) {
238
        NS_WARNING("VRDisplayHost::SubmitFrame failed to get a SurfaceTexture");
239
        return false;
240
      }
241
      *aTextureType = VRLayerTextureType::LayerTextureType_GeckoSurfaceTexture;
242
      *aTextureHandle = desc.handle();
243
      return true;
244
    }
245
#endif
246
0
    default: {
247
0
      MOZ_ASSERT(false);
248
0
      return false;
249
0
    }
250
0
  }
251
0
}
252
253
bool
254
VRDisplayExternal::SubmitFrame(const layers::SurfaceDescriptor& aTexture,
255
                               uint64_t aFrameId,
256
                               const gfx::Rect& aLeftEyeRect,
257
                               const gfx::Rect& aRightEyeRect)
258
0
{
259
0
  MOZ_ASSERT(mBrowserState.layerState[0].type == VRLayerType::LayerType_Stereo_Immersive);
260
0
  VRLayer_Stereo_Immersive& layer = mBrowserState.layerState[0].layer_stereo_immersive;
261
0
  if (!PopulateLayerTexture(aTexture, &layer.mTextureType, &layer.mTextureHandle)) {
262
0
    return false;
263
0
  }
264
0
  layer.mFrameId = aFrameId;
265
0
  layer.mInputFrameId = mDisplayInfo.mLastSensorState[mDisplayInfo.mFrameId % kVRMaxLatencyFrames].inputFrameID;
266
0
267
0
  layer.mLeftEyeRect.x = aLeftEyeRect.x;
268
0
  layer.mLeftEyeRect.y = aLeftEyeRect.y;
269
0
  layer.mLeftEyeRect.width = aLeftEyeRect.width;
270
0
  layer.mLeftEyeRect.height = aLeftEyeRect.height;
271
0
  layer.mRightEyeRect.x = aRightEyeRect.x;
272
0
  layer.mRightEyeRect.y = aRightEyeRect.y;
273
0
  layer.mRightEyeRect.width = aRightEyeRect.width;
274
0
  layer.mRightEyeRect.height = aRightEyeRect.height;
275
0
276
0
  PushState(true);
277
0
278
#if defined(MOZ_WIDGET_ANDROID)
279
  PullState([&]() {
280
    return (mDisplayInfo.mDisplayState.mLastSubmittedFrameId >= aFrameId) ||
281
            mDisplayInfo.mDisplayState.mSuppressFrames ||
282
            !mDisplayInfo.mDisplayState.mIsConnected;
283
  });
284
285
  if (mDisplayInfo.mDisplayState.mSuppressFrames || !mDisplayInfo.mDisplayState.mIsConnected) {
286
    // External implementation wants to supress frames, service has shut down or hardware has been disconnected.
287
    return false;
288
  }
289
#else
290
0
  while (mDisplayInfo.mDisplayState.mLastSubmittedFrameId < aFrameId) {
291
0
    if (PullState()) {
292
0
      if (mDisplayInfo.mDisplayState.mSuppressFrames || !mDisplayInfo.mDisplayState.mIsConnected) {
293
0
        // External implementation wants to supress frames, service has shut down or hardware has been disconnected.
294
0
        return false;
295
0
      }
296
0
    }
297
#ifdef XP_WIN
298
    Sleep(0);
299
#else
300
0
    sleep(0);
301
0
#endif
302
0
  }
303
0
#endif // defined(MOZ_WIDGET_ANDROID)
304
0
305
0
  return mDisplayInfo.mDisplayState.mLastSubmittedFrameSuccessful;
306
0
}
307
308
void
309
VRDisplayExternal::PushState(bool aNotifyCond)
310
0
{
311
0
  VRManager *vm = VRManager::Get();
312
0
  VRSystemManagerExternal* manager = vm->GetExternalManager();
313
0
  manager->PushState(&mBrowserState, aNotifyCond);
314
0
}
315
316
#if defined(MOZ_WIDGET_ANDROID)
317
bool
318
VRDisplayExternal::PullState(const std::function<bool()>& aWaitCondition)
319
{
320
  VRManager *vm = VRManager::Get();
321
  VRSystemManagerExternal* manager = vm->GetExternalManager();
322
  return manager->PullState(&mDisplayInfo.mDisplayState,
323
                            &mLastSensorState,
324
                            mDisplayInfo.mControllerState,
325
                            aWaitCondition);
326
}
327
#else
328
bool
329
VRDisplayExternal::PullState()
330
0
{
331
0
  VRManager *vm = VRManager::Get();
332
0
  VRSystemManagerExternal* manager = vm->GetExternalManager();
333
0
  return manager->PullState(&mDisplayInfo.mDisplayState,
334
0
                            &mLastSensorState,
335
0
                            mDisplayInfo.mControllerState);
336
0
}
337
#endif
338
339
VRSystemManagerExternal::VRSystemManagerExternal(VRExternalShmem* aAPIShmem /* = nullptr*/)
340
 : mExternalShmem(aAPIShmem)
341
#if !defined(MOZ_WIDGET_ANDROID)
342
 , mSameProcess(aAPIShmem != nullptr)
343
#endif
344
0
{
345
#if defined(XP_MACOSX)
346
  mShmemFD = 0;
347
#elif defined(XP_WIN)
348
  mShmemFile = NULL;
349
#elif defined(MOZ_WIDGET_ANDROID)
350
  mDoShutdown = false;
351
  mExternalStructFailed = false;
352
  mEnumerationCompleted = false;
353
#endif
354
355
0
  if (!aAPIShmem) {
356
0
    OpenShmem();
357
0
  }
358
0
}
359
360
VRSystemManagerExternal::~VRSystemManagerExternal()
361
0
{
362
0
  CloseShmem();
363
0
}
364
365
void
366
VRSystemManagerExternal::OpenShmem()
367
0
{
368
0
  if (mExternalShmem) {
369
0
    return;
370
#if defined(MOZ_WIDGET_ANDROID)
371
  } else if (mExternalStructFailed) {
372
    return;
373
#endif // defined(MOZ_WIDGET_ANDROID)
374
  }
375
0
376
#if defined(XP_MACOSX)
377
  if (mShmemFD == 0) {
378
    mShmemFD = shm_open(kShmemName, O_RDWR, S_IRUSR | S_IWUSR | S_IROTH | S_IWOTH);
379
  }
380
  if (mShmemFD <= 0) {
381
    mShmemFD = 0;
382
    return;
383
  }
384
385
  struct stat sb;
386
  fstat(mShmemFD, &sb);
387
  off_t length = sb.st_size;
388
  if (length < (off_t)sizeof(VRExternalShmem)) {
389
    // TODO - Implement logging
390
    CloseShmem();
391
    return;
392
  }
393
394
  mExternalShmem = (VRExternalShmem*)mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_SHARED, mShmemFD, 0);
395
  if (mExternalShmem == MAP_FAILED) {
396
    // TODO - Implement logging
397
    mExternalShmem = NULL;
398
    CloseShmem();
399
    return;
400
  }
401
402
#elif defined(XP_WIN)
403
  if (mShmemFile == NULL) {
404
    if (gfxPrefs::VRProcessEnabled()) {
405
      mShmemFile = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
406
                                      sizeof(VRExternalShmem), kShmemName);
407
      MOZ_ASSERT(GetLastError() == 0);
408
    } else {
409
      mShmemFile = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, kShmemName);
410
    }
411
412
    if (mShmemFile == NULL) {
413
      // TODO - Implement logging
414
      CloseShmem();
415
      return;
416
    }
417
  }
418
  LARGE_INTEGER length;
419
  length.QuadPart = sizeof(VRExternalShmem);
420
  mExternalShmem = (VRExternalShmem*)MapViewOfFile(mShmemFile, // handle to map object
421
    FILE_MAP_ALL_ACCESS,  // read/write permission
422
    0,
423
    0,
424
    length.QuadPart);
425
426
  if (mExternalShmem == NULL) {
427
    // TODO - Implement logging
428
    CloseShmem();
429
    return;
430
  }
431
#elif defined(MOZ_WIDGET_ANDROID)
432
  mExternalShmem = (VRExternalShmem*)mozilla::GeckoVRManager::GetExternalContext();
433
  if (!mExternalShmem) {
434
    return;
435
  }
436
  int32_t version = -1;
437
  int32_t size = 0;
438
  if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->systemMutex)) == 0) {
439
    version = mExternalShmem->version;
440
    size = mExternalShmem->size;
441
    pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->systemMutex));
442
  } else {
443
    return;
444
  }
445
  if (version != kVRExternalVersion) {
446
    mExternalShmem = nullptr;
447
    mExternalStructFailed = true;
448
    return;
449
  }
450
  if (size != sizeof(VRExternalShmem)) {
451
    mExternalShmem = nullptr;
452
    mExternalStructFailed = true;
453
    return;
454
  }
455
#endif
456
0
  CheckForShutdown();
457
0
}
458
459
void
460
VRSystemManagerExternal::CheckForShutdown()
461
0
{
462
#if defined(MOZ_WIDGET_ANDROID)
463
  if (mDoShutdown) {
464
    Shutdown();
465
  }
466
#else
467
0
  if (mExternalShmem) {
468
0
    if (mExternalShmem->generationA == -1 && mExternalShmem->generationB == -1) {
469
0
      Shutdown();
470
0
    }
471
0
  }
472
0
#endif // defined(MOZ_WIDGET_ANDROID)
473
0
}
474
475
void
476
VRSystemManagerExternal::CloseShmem()
477
0
{
478
0
#if !defined(MOZ_WIDGET_ANDROID)
479
0
  if (mSameProcess) {
480
0
    return;
481
0
  }
482
0
#endif
483
#if defined(XP_MACOSX)
484
  if (mExternalShmem) {
485
    munmap((void *)mExternalShmem, sizeof(VRExternalShmem));
486
    mExternalShmem = NULL;
487
  }
488
  if (mShmemFD) {
489
    close(mShmemFD);
490
  }
491
  mShmemFD = 0;
492
#elif defined(XP_WIN)
493
  if (mExternalShmem) {
494
    UnmapViewOfFile((void *)mExternalShmem);
495
    mExternalShmem = NULL;
496
  }
497
  if (mShmemFile) {
498
    CloseHandle(mShmemFile);
499
    mShmemFile = NULL;
500
  }
501
#elif defined(MOZ_WIDGET_ANDROID)
502
  mExternalShmem = NULL;
503
#endif
504
}
505
506
/*static*/ already_AddRefed<VRSystemManagerExternal>
507
VRSystemManagerExternal::Create(VRExternalShmem* aAPIShmem /* = nullptr*/)
508
0
{
509
0
  MOZ_ASSERT(NS_IsMainThread());
510
0
511
0
  if (!gfxPrefs::VREnabled()) {
512
0
    return nullptr;
513
0
  }
514
0
515
0
  if ((!gfxPrefs::VRExternalEnabled() && aAPIShmem == nullptr)
516
#if defined(XP_WIN)
517
      || !XRE_IsGPUProcess()
518
#endif
519
0
     ) {
520
0
    return nullptr;
521
0
  }
522
0
523
0
  RefPtr<VRSystemManagerExternal> manager = new VRSystemManagerExternal(aAPIShmem);
524
0
  return manager.forget();
525
0
}
526
527
void
528
VRSystemManagerExternal::Destroy()
529
0
{
530
0
  Shutdown();
531
0
}
532
533
void
534
VRSystemManagerExternal::Shutdown()
535
0
{
536
0
  if (mDisplay) {
537
0
    mDisplay = nullptr;
538
0
  }
539
0
  CloseShmem();
540
#if defined(MOZ_WIDGET_ANDROID)
541
  mDoShutdown = false;
542
#endif
543
}
544
545
void
546
VRSystemManagerExternal::NotifyVSync()
547
0
{
548
0
  VRSystemManager::NotifyVSync();
549
0
550
0
  CheckForShutdown();
551
0
552
0
  if (mDisplay) {
553
0
    mDisplay->Refresh();
554
0
  }
555
0
}
556
557
void
558
VRSystemManagerExternal::Enumerate()
559
0
{
560
0
  if (mDisplay == nullptr) {
561
0
    OpenShmem();
562
0
    if (mExternalShmem) {
563
0
      VRDisplayState displayState;
564
0
      memset(&displayState, 0, sizeof(VRDisplayState));
565
0
      // We must block until enumeration has completed in order
566
0
      // to signal that the WebVR promise should be resolved at the
567
0
      // right time.
568
#if defined(MOZ_WIDGET_ANDROID)
569
      PullState(&displayState, nullptr, nullptr, [&](){
570
        return mEnumerationCompleted;
571
      });
572
#else
573
0
      while (!PullState(&displayState)) {
574
#ifdef XP_WIN
575
        Sleep(0);
576
#else
577
        sleep(0);
578
0
#endif // XP_WIN
579
0
      }
580
0
#endif // defined(MOZ_WIDGET_ANDROID)
581
0
582
0
      if (displayState.mIsConnected) {
583
0
        mDisplay = new VRDisplayExternal(displayState);
584
0
      }
585
0
    }
586
0
  }
587
0
}
588
589
bool
590
VRSystemManagerExternal::ShouldInhibitEnumeration()
591
0
{
592
0
  if (VRSystemManager::ShouldInhibitEnumeration()) {
593
0
    return true;
594
0
  }
595
0
  if (mDisplay) {
596
0
    // When we find an a VR device, don't
597
0
    // allow any further enumeration as it
598
0
    // may get picked up redundantly by other
599
0
    // API's.
600
0
    return true;
601
0
  }
602
0
  return false;
603
0
}
604
605
void
606
VRSystemManagerExternal::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
607
0
{
608
0
  if (mDisplay) {
609
0
    aHMDResult.AppendElement(mDisplay);
610
0
  }
611
0
}
612
613
bool
614
VRSystemManagerExternal::GetIsPresenting()
615
0
{
616
0
  if (mDisplay) {
617
0
    VRDisplayInfo displayInfo(mDisplay->GetDisplayInfo());
618
0
    return displayInfo.GetPresentingGroups() != 0;
619
0
  }
620
0
621
0
  return false;
622
0
}
623
624
void
625
VRSystemManagerExternal::VibrateHaptic(uint32_t aControllerIdx,
626
                                      uint32_t aHapticIndex,
627
                                      double aIntensity,
628
                                      double aDuration,
629
                                      const VRManagerPromise& aPromise)
630
0
{
631
0
  // TODO - Implement this
632
0
}
633
634
void
635
VRSystemManagerExternal::StopVibrateHaptic(uint32_t aControllerIdx)
636
0
{
637
0
  // TODO - Implement this
638
0
}
639
640
void
641
VRSystemManagerExternal::GetControllers(nsTArray<RefPtr<VRControllerHost>>& aControllerResult)
642
0
{
643
0
  // Controller updates are handled in VRDisplayClient for VRSystemManagerExternal
644
0
  aControllerResult.Clear();
645
0
}
646
647
void
648
VRSystemManagerExternal::ScanForControllers()
649
0
{
650
0
  // Controller updates are handled in VRDisplayClient for VRSystemManagerExternal
651
0
  if (mDisplay) {
652
0
    mDisplay->Refresh();
653
0
  }
654
0
  return;
655
0
}
656
657
void
658
VRSystemManagerExternal::HandleInput()
659
0
{
660
0
  // Controller updates are handled in VRDisplayClient for VRSystemManagerExternal
661
0
  if (mDisplay) {
662
0
    mDisplay->Refresh();
663
0
  }
664
0
  return;
665
0
}
666
667
void
668
VRSystemManagerExternal::RemoveControllers()
669
0
{
670
0
  // Controller updates are handled in VRDisplayClient for VRSystemManagerExternal
671
0
}
672
673
674
#if defined(MOZ_WIDGET_ANDROID)
675
bool
676
VRSystemManagerExternal::PullState(VRDisplayState* aDisplayState,
677
                                   VRHMDSensorState* aSensorState /* = nullptr */,
678
                                   VRControllerState* aControllerState /* = nullptr */,
679
                                   const std::function<bool()>& aWaitCondition /* = nullptr */)
680
{
681
  MOZ_ASSERT(mExternalShmem);
682
  if (!mExternalShmem) {
683
    return false;
684
  }
685
  bool done = false;
686
  while(!done) {
687
    if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->systemMutex)) == 0) {
688
      while (true) {
689
        memcpy(aDisplayState, (void*)&(mExternalShmem->state.displayState), sizeof(VRDisplayState));
690
        if (aSensorState) {
691
          memcpy(aSensorState, (void*)&(mExternalShmem->state.sensorState), sizeof(VRHMDSensorState));
692
        }
693
        if (aControllerState) {
694
          memcpy(aControllerState, (void*)&(mExternalShmem->state.controllerState), sizeof(VRControllerState) * kVRControllerMaxCount);
695
        }
696
        mEnumerationCompleted = mExternalShmem->state.enumerationCompleted;
697
        mDoShutdown = aDisplayState->shutdown;
698
        if (!aWaitCondition || aWaitCondition()) {
699
          done = true;
700
          break;
701
        }
702
        // Block current thead using the condition variable until data changes
703
        pthread_cond_wait((pthread_cond_t*)&mExternalShmem->systemCond, (pthread_mutex_t*)&mExternalShmem->systemMutex);
704
      }
705
      pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->systemMutex));
706
    } else if (!aWaitCondition) {
707
      // pthread_mutex_lock failed and we are not waiting for a condition to exit from PullState call.
708
      // return false to indicate that PullState call failed
709
      return false;
710
    }
711
  }
712
  return true;
713
}
714
#else 
715
bool
716
VRSystemManagerExternal::PullState(VRDisplayState* aDisplayState,
717
                                   VRHMDSensorState* aSensorState /* = nullptr */,
718
                                   VRControllerState* aControllerState /* = nullptr */)
719
0
{
720
0
  bool success = false;
721
0
  MOZ_ASSERT(mExternalShmem);
722
0
  if (mExternalShmem) {
723
0
    VRExternalShmem tmp;
724
0
    memcpy(&tmp, (void *)mExternalShmem, sizeof(VRExternalShmem));
725
0
    if (tmp.generationA == tmp.generationB && tmp.generationA != 0 && tmp.generationA != -1 && tmp.state.enumerationCompleted) {
726
0
      memcpy(aDisplayState, &tmp.state.displayState, sizeof(VRDisplayState));
727
0
      if (aSensorState) {
728
0
        memcpy(aSensorState, &tmp.state.sensorState, sizeof(VRHMDSensorState));
729
0
      }
730
0
      if (aControllerState) {
731
0
        memcpy(aControllerState, (void*)&(mExternalShmem->state.controllerState), sizeof(VRControllerState) * kVRControllerMaxCount);
732
0
      }
733
0
      success = true;
734
0
    }
735
0
  }
736
0
737
0
  return success;
738
0
}
739
#endif // defined(MOZ_WIDGET_ANDROID)
740
741
742
void
743
VRSystemManagerExternal::PushState(VRBrowserState* aBrowserState, bool aNotifyCond)
744
0
{
745
0
  MOZ_ASSERT(aBrowserState);
746
0
  MOZ_ASSERT(mExternalShmem);
747
0
  if (mExternalShmem) {
748
#if defined(MOZ_WIDGET_ANDROID)
749
    if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->browserMutex)) == 0) {
750
      memcpy((void *)&(mExternalShmem->browserState), aBrowserState, sizeof(VRBrowserState));
751
      if (aNotifyCond) {
752
        pthread_cond_signal((pthread_cond_t*)&(mExternalShmem->browserCond));
753
      }
754
      pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->browserMutex));
755
    }
756
#else
757
    mExternalShmem->browserGenerationA++;
758
0
    memcpy((void *)&(mExternalShmem->browserState), (void *)aBrowserState, sizeof(VRBrowserState));
759
0
    mExternalShmem->browserGenerationB++;
760
0
#endif // defined(MOZ_WIDGET_ANDROID)
761
0
  }
762
0
}