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