gfx/vr/gfxVR.h
author Daosheng Mu <daoshengmu@gmail.com>
Fri, 28 Dec 2018 22:09:44 +0000
changeset 509582 ec8667678f3a7fa4d6259b070a35a4c4a5c14209
parent 505383 6f3709b3878117466168c40affa7bca0b60cf75b
child 510252 68dc096dab039ddc824d285c6511b033abd2b6c3
permissions -rw-r--r--
Bug 1430040 - Part 4: Make the parent process keep the OpenVR controller manifest info when VR process is enabled. r=kip Differential Revision: https://phabricator.services.mozilla.com/D15419

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef GFX_VR_H
#define GFX_VR_H

#include "moz_external_vr.h"
#include "nsTArray.h"
#include "nsString.h"
#include "nsCOMPtr.h"
#include "mozilla/RefPtr.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/Atomics.h"
#include "mozilla/EnumeratedArray.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/TypedEnumBits.h"

namespace mozilla {
namespace layers {
class PTextureParent;
}
namespace dom {
enum class GamepadMappingType : uint8_t;
enum class GamepadHand : uint8_t;
struct GamepadPoseState;
}  // namespace dom
namespace gfx {
class VRLayerParent;
class VRDisplayHost;
class VRControllerHost;
class VRManagerPromise;

// The maximum number of frames of latency that we would expect before we
// should give up applying pose prediction.
// If latency is greater than one second, then the experience is not likely
// to be corrected by pose prediction.  Setting this value too
// high may result in unnecessary memory allocation.
// As the current fastest refresh rate is 90hz, 100 is selected as a
// conservative value.
static const int kVRMaxLatencyFrames = 100;

enum class VRDeviceType : uint16_t {
  Oculus,
  OpenVR,
  OSVR,
  GVR,
  Puppet,
  External,
  NumVRDeviceTypes
};

enum class OpenVRControllerType : uint16_t {
  Vive,
  WMR,
  Knuckles,
  NumOpenVRControllerTypes
};

struct VRDisplayInfo {
  uint32_t mDisplayID;
  VRDeviceType mType;
  uint32_t mPresentingGroups;
  uint32_t mGroupMask;
  uint64_t mFrameId;
  VRDisplayState mDisplayState;
  VRControllerState mControllerState[kVRControllerMaxCount];

  VRHMDSensorState mLastSensorState[kVRMaxLatencyFrames];
  TimeStamp mLastFrameStart[kVRMaxLatencyFrames];
  const VRHMDSensorState& GetSensorState() const {
    return mLastSensorState[mFrameId % kVRMaxLatencyFrames];
  }

  VRDeviceType GetType() const { return mType; }
  uint32_t GetDisplayID() const { return mDisplayID; }
  const char* GetDisplayName() const { return mDisplayState.mDisplayName; }
  VRDisplayCapabilityFlags GetCapabilities() const {
    return mDisplayState.mCapabilityFlags;
  }

  const IntSize SuggestedEyeResolution() const;
  const Point3D GetEyeTranslation(uint32_t whichEye) const;
  const VRFieldOfView& GetEyeFOV(uint32_t whichEye) const {
    return mDisplayState.mEyeFOV[whichEye];
  }
  bool GetIsConnected() const { return mDisplayState.mIsConnected; }
  bool GetIsMounted() const { return mDisplayState.mIsMounted; }
  uint32_t GetPresentingGroups() const { return mPresentingGroups; }
  uint32_t GetGroupMask() const { return mGroupMask; }
  const Size GetStageSize() const;
  const Matrix4x4 GetSittingToStandingTransform() const;
  uint64_t GetFrameId() const { return mFrameId; }

  bool operator==(const VRDisplayInfo& other) const {
    for (size_t i = 0; i < kVRMaxLatencyFrames; i++) {
      if (mLastSensorState[i] != other.mLastSensorState[i]) {
        return false;
      }
    }
    // Note that mDisplayState and mControllerState are asserted to be POD
    // types, so memcmp is safe
    return mType == other.mType && mDisplayID == other.mDisplayID &&
           memcmp(&mDisplayState, &other.mDisplayState,
                  sizeof(VRDisplayState)) == 0 &&
           memcmp(mControllerState, other.mControllerState,
                  sizeof(VRControllerState) * kVRControllerMaxCount) == 0 &&
           mPresentingGroups == other.mPresentingGroups &&
           mGroupMask == other.mGroupMask && mFrameId == other.mFrameId;
  }

  bool operator!=(const VRDisplayInfo& other) const {
    return !(*this == other);
  }
};

struct VRSubmitFrameResultInfo {
  VRSubmitFrameResultInfo()
      : mFormat(SurfaceFormat::UNKNOWN), mFrameNum(0), mWidth(0), mHeight(0) {}

  nsCString mBase64Image;
  SurfaceFormat mFormat;
  uint64_t mFrameNum;
  uint32_t mWidth;
  uint32_t mHeight;
};

struct VRControllerInfo {
  VRDeviceType GetType() const { return mType; }
  uint32_t GetControllerID() const { return mControllerID; }
  const char* GetControllerName() const {
    return mControllerState.controllerName;
  }
  dom::GamepadMappingType GetMappingType() const { return mMappingType; }
  uint32_t GetDisplayID() const { return mDisplayID; }
  dom::GamepadHand GetHand() const { return mControllerState.hand; }
  uint32_t GetNumButtons() const { return mControllerState.numButtons; }
  uint32_t GetNumAxes() const { return mControllerState.numAxes; }
  uint32_t GetNumHaptics() const { return mControllerState.numHaptics; }

  uint32_t mControllerID;
  VRDeviceType mType;
  dom::GamepadMappingType mMappingType;
  uint32_t mDisplayID;
  VRControllerState mControllerState;
  bool operator==(const VRControllerInfo& other) const {
    // Note that mControllerState is asserted to be a POD type, so memcmp is
    // safe
    return mType == other.mType && mControllerID == other.mControllerID &&
           memcmp(&mControllerState, &other.mControllerState,
                  sizeof(VRControllerState)) == 0 &&
           mMappingType == other.mMappingType && mDisplayID == other.mDisplayID;
  }

  bool operator!=(const VRControllerInfo& other) const {
    return !(*this == other);
  }
};

struct VRTelemetry {
  VRTelemetry() : mLastDroppedFrameCount(-1) {}

  void Clear() {
    mPresentationStart = TimeStamp();
    mLastDroppedFrameCount = -1;
  }

  bool IsLastDroppedFrameValid() { return (mLastDroppedFrameCount != -1); }

  TimeStamp mPresentationStart;
  int32_t mLastDroppedFrameCount;
};

class VRSystemManager {
 public:
  static uint32_t AllocateDisplayID();
  static uint32_t AllocateControllerID();

 protected:
  static Atomic<uint32_t> sDisplayBase;
  static Atomic<uint32_t> sControllerBase;

 public:
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRSystemManager)

  virtual void Destroy() = 0;
  virtual void Shutdown() = 0;
  virtual void Enumerate() = 0;
  virtual void NotifyVSync();
  virtual void Run1msTasks(double aDeltaTime);
  virtual void Run10msTasks();
  virtual void Run100msTasks();
  virtual bool ShouldInhibitEnumeration();
  virtual void GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult) = 0;
  virtual bool GetIsPresenting() = 0;
  virtual void HandleInput() = 0;
  virtual void GetControllers(
      nsTArray<RefPtr<VRControllerHost>>& aControllerResult) = 0;
  virtual void ScanForControllers() = 0;
  virtual void RemoveControllers() = 0;
  virtual void VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
                             double aIntensity, double aDuration,
                             const VRManagerPromise& aPromise) = 0;
  virtual void StopVibrateHaptic(uint32_t aControllerIdx) = 0;
  void NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed,
                      bool aTouched, double aValue);
  void NewAxisMove(uint32_t aIndex, uint32_t aAxis, double aValue);
  void NewPoseState(uint32_t aIndex, const dom::GamepadPoseState& aPose);
  void NewHandChangeEvent(uint32_t aIndex, const dom::GamepadHand aHand);
  void AddGamepad(const VRControllerInfo& controllerInfo);
  void RemoveGamepad(uint32_t aIndex);

 protected:
  VRSystemManager() : mControllerCount(0) {}
  virtual ~VRSystemManager() = default;

  uint32_t mControllerCount;
};

}  // namespace gfx
}  // namespace mozilla

#endif /* GFX_VR_H */