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 #ifndef GFX_VR_H
8 #define GFX_VR_H
9 
10 #include "nsTArray.h"
11 #include "nsString.h"
12 #include "nsCOMPtr.h"
13 #include "mozilla/RefPtr.h"
14 #include "mozilla/gfx/2D.h"
15 #include "mozilla/Atomics.h"
16 #include "mozilla/EnumeratedArray.h"
17 #include "mozilla/TimeStamp.h"
18 #include "mozilla/TypedEnumBits.h"
19 
20 namespace mozilla {
21 namespace layers {
22 class PTextureParent;
23 }
24 namespace dom {
25 enum class GamepadMappingType : uint8_t;
26 enum class GamepadHand : uint8_t;
27 struct GamepadPoseState;
28 }  // namespace dom
29 namespace gfx {
30 class VRLayerParent;
31 class VRDisplayHost;
32 class VRControllerHost;
33 class VRManagerPromise;
34 
35 enum class VRDeviceType : uint16_t {
36   Oculus,
37   OpenVR,
38   OSVR,
39   GVR,
40   Puppet,
41   NumVRDeviceTypes
42 };
43 
44 enum class VRDisplayCapabilityFlags : uint16_t {
45   Cap_None = 0,
46   /**
47    * Cap_Position is set if the VRDisplay is capable of tracking its position.
48    */
49   Cap_Position = 1 << 1,
50   /**
51    * Cap_Orientation is set if the VRDisplay is capable of tracking its
52    * orientation.
53    */
54   Cap_Orientation = 1 << 2,
55   /**
56    * Cap_Present is set if the VRDisplay is capable of presenting content to an
57    * HMD or similar device.  Can be used to indicate "magic window" devices that
58    * are capable of 6DoF tracking but for which requestPresent is not
59    * meaningful. If false then calls to requestPresent should always fail, and
60    * getEyeParameters should return null.
61    */
62   Cap_Present = 1 << 3,
63   /**
64    * Cap_External is set if the VRDisplay is separate from the device's
65    * primary display. If presenting VR content will obscure
66    * other content on the device, this should be un-set. When
67    * un-set, the application should not attempt to mirror VR content
68    * or update non-VR UI because that content will not be visible.
69    */
70   Cap_External = 1 << 4,
71   /**
72    * Cap_AngularAcceleration is set if the VRDisplay is capable of tracking its
73    * angular acceleration.
74    */
75   Cap_AngularAcceleration = 1 << 5,
76   /**
77    * Cap_LinearAcceleration is set if the VRDisplay is capable of tracking its
78    * linear acceleration.
79    */
80   Cap_LinearAcceleration = 1 << 6,
81   /**
82    * Cap_StageParameters is set if the VRDisplay is capable of room scale VR
83    * and can report the StageParameters to describe the space.
84    */
85   Cap_StageParameters = 1 << 7,
86   /**
87    * Cap_MountDetection is set if the VRDisplay is capable of sensing when the
88    * user is wearing the device.
89    */
90   Cap_MountDetection = 1 << 8,
91   /**
92    * Cap_All used for validity checking during IPC serialization
93    */
94   Cap_All = (1 << 9) - 1
95 };
96 
97 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(VRDisplayCapabilityFlags)
98 
99 struct VRFieldOfView {
100   VRFieldOfView() = default;
VRFieldOfViewVRFieldOfView101   VRFieldOfView(double up, double right, double down, double left)
102       : upDegrees(up),
103         rightDegrees(right),
104         downDegrees(down),
105         leftDegrees(left) {}
106 
SetFromTanRadiansVRFieldOfView107   void SetFromTanRadians(double up, double right, double down, double left) {
108     upDegrees = atan(up) * 180.0 / M_PI;
109     rightDegrees = atan(right) * 180.0 / M_PI;
110     downDegrees = atan(down) * 180.0 / M_PI;
111     leftDegrees = atan(left) * 180.0 / M_PI;
112   }
113 
114   bool operator==(const VRFieldOfView& other) const {
115     return other.upDegrees == upDegrees && other.downDegrees == downDegrees &&
116            other.rightDegrees == rightDegrees &&
117            other.leftDegrees == leftDegrees;
118   }
119 
120   bool operator!=(const VRFieldOfView& other) const {
121     return !(*this == other);
122   }
123 
IsZeroVRFieldOfView124   bool IsZero() const {
125     return upDegrees == 0.0 || rightDegrees == 0.0 || downDegrees == 0.0 ||
126            leftDegrees == 0.0;
127   }
128 
129   Matrix4x4 ConstructProjectionMatrix(float zNear, float zFar,
130                                       bool rightHanded) const;
131 
132   double upDegrees;
133   double rightDegrees;
134   double downDegrees;
135   double leftDegrees;
136 };
137 
138 struct VRHMDSensorState {
139   int64_t inputFrameID;
140   double timestamp;
141   VRDisplayCapabilityFlags flags;
142 
143   // These members will only change with inputFrameID:
144   float orientation[4];
145   float position[3];
146   float leftViewMatrix[16];
147   float rightViewMatrix[16];
148   float angularVelocity[3];
149   float angularAcceleration[3];
150   float linearVelocity[3];
151   float linearAcceleration[3];
152 
ClearVRHMDSensorState153   void Clear() { memset(this, 0, sizeof(VRHMDSensorState)); }
154 
155   bool operator==(const VRHMDSensorState& other) const {
156     return inputFrameID == other.inputFrameID && timestamp == other.timestamp;
157   }
158 
159   bool operator!=(const VRHMDSensorState& other) const {
160     return !(*this == other);
161   }
162   void CalcViewMatrices(const gfx::Matrix4x4* aHeadToEyeTransforms);
163 };
164 
165 // The maximum number of frames of latency that we would expect before we
166 // should give up applying pose prediction.
167 // If latency is greater than one second, then the experience is not likely
168 // to be corrected by pose prediction.  Setting this value too
169 // high may result in unnecessary memory allocation.
170 // As the current fastest refresh rate is 90hz, 100 is selected as a
171 // conservative value.
172 static const int kVRMaxLatencyFrames = 100;
173 
174 // We assign VR presentations to groups with a bitmask.
175 // Currently, we will only display either content or chrome.
176 // Later, we will have more groups to support VR home spaces and
177 // multitasking environments.
178 // These values are not exposed to regular content and only affect
179 // chrome-only API's.  They may be changed at any time.
180 static const uint32_t kVRGroupNone = 0;
181 static const uint32_t kVRGroupContent = 1 << 0;
182 static const uint32_t kVRGroupChrome = 1 << 1;
183 static const uint32_t kVRGroupAll = 0xffffffff;
184 
185 struct VRDisplayInfo {
GetTypeVRDisplayInfo186   VRDeviceType GetType() const { return mType; }
GetDisplayIDVRDisplayInfo187   uint32_t GetDisplayID() const { return mDisplayID; }
GetDisplayNameVRDisplayInfo188   const nsCString& GetDisplayName() const { return mDisplayName; }
GetCapabilitiesVRDisplayInfo189   VRDisplayCapabilityFlags GetCapabilities() const { return mCapabilityFlags; }
190 
SuggestedEyeResolutionVRDisplayInfo191   const IntSize& SuggestedEyeResolution() const { return mEyeResolution; }
GetEyeTranslationVRDisplayInfo192   const Point3D& GetEyeTranslation(uint32_t whichEye) const {
193     return mEyeTranslation[whichEye];
194   }
GetEyeFOVVRDisplayInfo195   const VRFieldOfView& GetEyeFOV(uint32_t whichEye) const {
196     return mEyeFOV[whichEye];
197   }
GetIsConnectedVRDisplayInfo198   bool GetIsConnected() const { return mIsConnected; }
GetIsMountedVRDisplayInfo199   bool GetIsMounted() const { return mIsMounted; }
GetPresentingGroupsVRDisplayInfo200   uint32_t GetPresentingGroups() const { return mPresentingGroups; }
GetGroupMaskVRDisplayInfo201   uint32_t GetGroupMask() const { return mGroupMask; }
GetStageSizeVRDisplayInfo202   const Size& GetStageSize() const { return mStageSize; }
GetSittingToStandingTransformVRDisplayInfo203   const Matrix4x4& GetSittingToStandingTransform() const {
204     return mSittingToStandingTransform;
205   }
GetFrameIdVRDisplayInfo206   uint64_t GetFrameId() const { return mFrameId; }
207 
208   enum Eye { Eye_Left, Eye_Right, NumEyes };
209 
210   uint32_t mDisplayID;
211   VRDeviceType mType;
212   nsCString mDisplayName;
213   VRDisplayCapabilityFlags mCapabilityFlags;
214   VRFieldOfView mEyeFOV[VRDisplayInfo::NumEyes];
215   Point3D mEyeTranslation[VRDisplayInfo::NumEyes];
216   IntSize mEyeResolution;
217   bool mIsConnected;
218   bool mIsMounted;
219   uint32_t mPresentingGroups;
220   uint32_t mGroupMask;
221   Size mStageSize;
222   Matrix4x4 mSittingToStandingTransform;
223   uint64_t mFrameId;
224   uint32_t mPresentingGeneration;
225   VRHMDSensorState mLastSensorState[kVRMaxLatencyFrames];
226 
227   bool operator==(const VRDisplayInfo& other) const {
228     for (size_t i = 0; i < kVRMaxLatencyFrames; i++) {
229       if (mLastSensorState[i] != other.mLastSensorState[i]) {
230         return false;
231       }
232     }
233     return mType == other.mType && mDisplayID == other.mDisplayID &&
234            mDisplayName == other.mDisplayName &&
235            mCapabilityFlags == other.mCapabilityFlags &&
236            mEyeResolution == other.mEyeResolution &&
237            mIsConnected == other.mIsConnected &&
238            mIsMounted == other.mIsMounted &&
239            mPresentingGroups == other.mPresentingGroups &&
240            mGroupMask == other.mGroupMask && mEyeFOV[0] == other.mEyeFOV[0] &&
241            mEyeFOV[1] == other.mEyeFOV[1] &&
242            mEyeTranslation[0] == other.mEyeTranslation[0] &&
243            mEyeTranslation[1] == other.mEyeTranslation[1] &&
244            mStageSize == other.mStageSize &&
245            mSittingToStandingTransform == other.mSittingToStandingTransform &&
246            mFrameId == other.mFrameId &&
247            mPresentingGeneration == other.mPresentingGeneration;
248   }
249 
250   bool operator!=(const VRDisplayInfo& other) const {
251     return !(*this == other);
252   }
253 
GetSensorStateVRDisplayInfo254   const VRHMDSensorState& GetSensorState() const {
255     return mLastSensorState[mFrameId % kVRMaxLatencyFrames];
256   }
257 };
258 
259 struct VRSubmitFrameResultInfo {
VRSubmitFrameResultInfoVRSubmitFrameResultInfo260   VRSubmitFrameResultInfo() : mFrameNum(0), mWidth(0), mHeight(0) {}
261 
262   nsCString mBase64Image;
263   SurfaceFormat mFormat;
264   uint64_t mFrameNum;
265   uint32_t mWidth;
266   uint32_t mHeight;
267 };
268 
269 struct VRControllerInfo {
GetTypeVRControllerInfo270   VRDeviceType GetType() const { return mType; }
GetControllerIDVRControllerInfo271   uint32_t GetControllerID() const { return mControllerID; }
GetControllerNameVRControllerInfo272   const nsCString& GetControllerName() const { return mControllerName; }
GetMappingTypeVRControllerInfo273   dom::GamepadMappingType GetMappingType() const { return mMappingType; }
GetDisplayIDVRControllerInfo274   uint32_t GetDisplayID() const { return mDisplayID; }
GetHandVRControllerInfo275   dom::GamepadHand GetHand() const { return mHand; }
GetNumButtonsVRControllerInfo276   uint32_t GetNumButtons() const { return mNumButtons; }
GetNumAxesVRControllerInfo277   uint32_t GetNumAxes() const { return mNumAxes; }
GetNumHapticsVRControllerInfo278   uint32_t GetNumHaptics() const { return mNumHaptics; }
279 
280   uint32_t mControllerID;
281   VRDeviceType mType;
282   nsCString mControllerName;
283   dom::GamepadMappingType mMappingType;
284   uint32_t mDisplayID;
285   dom::GamepadHand mHand;
286   uint32_t mNumButtons;
287   uint32_t mNumAxes;
288   uint32_t mNumHaptics;
289 
290   bool operator==(const VRControllerInfo& other) const {
291     return mType == other.mType && mControllerID == other.mControllerID &&
292            mControllerName == other.mControllerName &&
293            mMappingType == other.mMappingType &&
294            mDisplayID == other.mDisplayID && mHand == other.mHand &&
295            mNumButtons == other.mNumButtons && mNumAxes == other.mNumAxes &&
296            mNumHaptics == other.mNumHaptics;
297   }
298 
299   bool operator!=(const VRControllerInfo& other) const {
300     return !(*this == other);
301   }
302 };
303 
304 struct VRTelemetry {
VRTelemetryVRTelemetry305   VRTelemetry() : mLastDroppedFrameCount(-1) {}
306 
ClearVRTelemetry307   void Clear() {
308     mPresentationStart = TimeStamp();
309     mLastDroppedFrameCount = -1;
310   }
311 
IsLastDroppedFrameValidVRTelemetry312   bool IsLastDroppedFrameValid() { return (mLastDroppedFrameCount != -1); }
313 
314   TimeStamp mPresentationStart;
315   int32_t mLastDroppedFrameCount;
316 };
317 
318 class VRSystemManager {
319  public:
320   static uint32_t AllocateDisplayID();
321   static uint32_t AllocateControllerID();
322 
323  protected:
324   static Atomic<uint32_t> sDisplayBase;
325   static Atomic<uint32_t> sControllerBase;
326 
327  public:
328   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRSystemManager)
329 
330   virtual void Destroy() = 0;
331   virtual void Shutdown() = 0;
332   virtual void Enumerate() = 0;
333   virtual void NotifyVSync();
334   virtual bool ShouldInhibitEnumeration();
335   virtual void GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult) = 0;
336   virtual bool GetIsPresenting() = 0;
337   virtual void HandleInput() = 0;
338   virtual void GetControllers(
339       nsTArray<RefPtr<VRControllerHost>>& aControllerResult) = 0;
340   virtual void ScanForControllers() = 0;
341   virtual void RemoveControllers() = 0;
342   virtual void VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
343                              double aIntensity, double aDuration,
344                              const VRManagerPromise& aPromise) = 0;
345   virtual void StopVibrateHaptic(uint32_t aControllerIdx) = 0;
346   void NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed,
347                       bool aTouched, double aValue);
348   void NewAxisMove(uint32_t aIndex, uint32_t aAxis, double aValue);
349   void NewPoseState(uint32_t aIndex, const dom::GamepadPoseState& aPose);
350   void NewHandChangeEvent(uint32_t aIndex, const dom::GamepadHand aHand);
351   void AddGamepad(const VRControllerInfo& controllerInfo);
352   void RemoveGamepad(uint32_t aIndex);
353 
354  protected:
VRSystemManager()355   VRSystemManager() : mControllerCount(0) {}
356   virtual ~VRSystemManager() = default;
357 
358   uint32_t mControllerCount;
359 };
360 
361 }  // namespace gfx
362 }  // namespace mozilla
363 
364 #endif /* GFX_VR_H */
365