diff options
Diffstat (limited to 'gfx/vr/external_api')
-rw-r--r-- | gfx/vr/external_api/moz_external_vr.h | 670 |
1 files changed, 670 insertions, 0 deletions
diff --git a/gfx/vr/external_api/moz_external_vr.h b/gfx/vr/external_api/moz_external_vr.h new file mode 100644 index 0000000000..1727e1e540 --- /dev/null +++ b/gfx/vr/external_api/moz_external_vr.h @@ -0,0 +1,670 @@ +/* -*- 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_EXTERNAL_API_H +#define GFX_VR_EXTERNAL_API_H + +#define GFX_VR_EIGHTCC(c1, c2, c3, c4, c5, c6, c7, c8) \ + ((uint64_t)(c1) << 56 | (uint64_t)(c2) << 48 | (uint64_t)(c3) << 40 | \ + (uint64_t)(c4) << 32 | (uint64_t)(c5) << 24 | (uint64_t)(c6) << 16 | \ + (uint64_t)(c7) << 8 | (uint64_t)(c8)) + +#ifdef MOZILLA_INTERNAL_API +# define __STDC_WANT_LIB_EXT1__ 1 +// __STDC_WANT_LIB_EXT1__ required for memcpy_s +# include <stdlib.h> +# include <string.h> +# include "mozilla/TypedEnumBits.h" +# include "mozilla/gfx/2D.h" +# include <stddef.h> +# include <stdint.h> +# include <type_traits> +#endif // MOZILLA_INTERNAL_API + +#if defined(__ANDROID__) +# include <pthread.h> +#endif // defined(__ANDROID__) + +#include <cstdint> +#include <type_traits> + +namespace mozilla { +#ifdef MOZILLA_INTERNAL_API +namespace dom { +enum class GamepadHand : uint8_t; +enum class GamepadCapabilityFlags : uint16_t; +} // namespace dom +#endif // MOZILLA_INTERNAL_API +namespace gfx { + +// If there is any change of "SHMEM_VERSION" or "kVRExternalVersion", +// we need to change both of them at the same time. + +// TODO: we might need to use different names for the mutexes +// and mapped files if we have both release and nightlies +// running at the same time? Or...what if we have multiple +// release builds running on same machine? (Bug 1563232) +#define SHMEM_VERSION "0.0.11" +static const int32_t kVRExternalVersion = 18; + +// We assign VR presentations to groups with a bitmask. +// Currently, we will only display either content or chrome. +// Later, we will have more groups to support VR home spaces and +// multitasking environments. +// These values are not exposed to regular content and only affect +// chrome-only API's. They may be changed at any time. +static const uint32_t kVRGroupNone = 0; +static const uint32_t kVRGroupContent = 1 << 0; +static const uint32_t kVRGroupChrome = 1 << 1; +static const uint32_t kVRGroupAll = 0xffffffff; + +static const int kVRDisplayNameMaxLen = 256; +static const int kVRControllerNameMaxLen = 256; +static const int kVRControllerMaxCount = 16; +static const int kVRControllerMaxButtons = 64; +static const int kVRControllerMaxAxis = 16; +static const int kVRLayerMaxCount = 8; +static const int kVRHapticsMaxCount = 32; + +#if defined(__ANDROID__) +typedef uint64_t VRLayerTextureHandle; +#elif defined(XP_MACOSX) +typedef uint32_t VRLayerTextureHandle; +#else +typedef void* VRLayerTextureHandle; +#endif + +struct Point3D_POD { + float x; + float y; + float z; +}; + +struct IntSize_POD { + int32_t width; + int32_t height; +}; + +struct FloatSize_POD { + float width; + float height; +}; + +#ifndef MOZILLA_INTERNAL_API + +enum class ControllerHand : uint8_t { _empty, Left, Right, EndGuard_ }; + +enum class ControllerCapabilityFlags : uint16_t { + Cap_None = 0, + /** + * Cap_Position is set if the Gamepad is capable of tracking its position. + */ + Cap_Position = 1 << 1, + /** + * Cap_Orientation is set if the Gamepad is capable of tracking its + * orientation. + */ + Cap_Orientation = 1 << 2, + /** + * Cap_AngularAcceleration is set if the Gamepad is capable of tracking its + * angular acceleration. + */ + Cap_AngularAcceleration = 1 << 3, + /** + * Cap_LinearAcceleration is set if the Gamepad is capable of tracking its + * linear acceleration. + */ + Cap_LinearAcceleration = 1 << 4, + /** + * Cap_TargetRaySpacePosition is set if the Gamepad has a grip space position. + */ + Cap_GripSpacePosition = 1 << 5, + /** + * Cap_PositionEmulated is set if the XRInputSoruce is capable of setting a + * emulated position (e.g. neck model) even if still doesn't support 6DOF + * tracking. + */ + Cap_PositionEmulated = 1 << 6, + /** + * Cap_All used for validity checking during IPC serialization + */ + Cap_All = (1 << 7) - 1 +}; + +#endif // ifndef MOZILLA_INTERNAL_API + +enum class VRControllerType : uint8_t { + _empty, + HTCVive, + HTCViveCosmos, + HTCViveFocus, + HTCViveFocusPlus, + MSMR, + ValveIndex, + OculusGo, + OculusTouch, + OculusTouch2, + PicoGaze, + PicoG2, + PicoNeo2, + _end +}; + +enum class TargetRayMode : uint8_t { Gaze, TrackedPointer, Screen }; + +enum class GamepadMappingType : uint8_t { _empty, Standard, XRStandard }; + +enum class VRDisplayBlendMode : uint8_t { Opaque, Additive, AlphaBlend }; + +enum class VRDisplayCapabilityFlags : uint16_t { + Cap_None = 0, + /** + * Cap_Position is set if the VRDisplay is capable of tracking its position. + */ + Cap_Position = 1 << 1, + /** + * Cap_Orientation is set if the VRDisplay is capable of tracking its + * orientation. + */ + Cap_Orientation = 1 << 2, + /** + * Cap_Present is set if the VRDisplay is capable of presenting content to an + * HMD or similar device. Can be used to indicate "magic window" devices that + * are capable of 6DoF tracking but for which requestPresent is not + * meaningful. If false then calls to requestPresent should always fail, and + * getEyeParameters should return null. + */ + Cap_Present = 1 << 3, + /** + * Cap_External is set if the VRDisplay is separate from the device's + * primary display. If presenting VR content will obscure + * other content on the device, this should be un-set. When + * un-set, the application should not attempt to mirror VR content + * or update non-VR UI because that content will not be visible. + */ + Cap_External = 1 << 4, + /** + * Cap_AngularAcceleration is set if the VRDisplay is capable of tracking its + * angular acceleration. + */ + Cap_AngularAcceleration = 1 << 5, + /** + * Cap_LinearAcceleration is set if the VRDisplay is capable of tracking its + * linear acceleration. + */ + Cap_LinearAcceleration = 1 << 6, + /** + * Cap_StageParameters is set if the VRDisplay is capable of room scale VR + * and can report the StageParameters to describe the space. + */ + Cap_StageParameters = 1 << 7, + /** + * Cap_MountDetection is set if the VRDisplay is capable of sensing when the + * user is wearing the device. + */ + Cap_MountDetection = 1 << 8, + /** + * Cap_PositionEmulated is set if the VRDisplay is capable of setting a + * emulated position (e.g. neck model) even if still doesn't support 6DOF + * tracking. + */ + Cap_PositionEmulated = 1 << 9, + /** + * Cap_Inline is set if the device can be used for WebXR inline sessions + * where the content is displayed within an element on the page. + */ + Cap_Inline = 1 << 10, + /** + * Cap_ImmersiveVR is set if the device can give exclusive access to the + * XR device display and that content is not intended to be integrated + * with the user's environment + */ + Cap_ImmersiveVR = 1 << 11, + /** + * Cap_ImmersiveAR is set if the device can give exclusive access to the + * XR device display and that content is intended to be integrated with + * the user's environment. + */ + Cap_ImmersiveAR = 1 << 12, + /** + * Cap_UseDepthValues is set if the device will use the depth values of the + * submitted frames if provided. How the depth values are used is determined + * by the VR runtime. Often the depth is used for occlusion of system UI + * or to enable more effective asynchronous reprojection of frames. + */ + Cap_UseDepthValues = 1 << 13, + /** + * Cap_All used for validity checking during IPC serialization + */ + Cap_All = (1 << 14) - 1 +}; + +#ifdef MOZILLA_INTERNAL_API +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(VRDisplayCapabilityFlags) +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(VRDisplayBlendMode) +#endif // MOZILLA_INTERNAL_API + +struct VRPose { + float orientation[4]; + float position[3]; + float angularVelocity[3]; + float angularAcceleration[3]; + float linearVelocity[3]; + float linearAcceleration[3]; +}; + +struct VRHMDSensorState { + uint64_t inputFrameID; + double timestamp; + VRDisplayCapabilityFlags flags; + + // These members will only change with inputFrameID: + VRPose pose; + float leftViewMatrix[16]; + float rightViewMatrix[16]; + +#ifdef MOZILLA_INTERNAL_API + + void Clear() { memset(this, 0, sizeof(VRHMDSensorState)); } + + bool operator==(const VRHMDSensorState& other) const { + return inputFrameID == other.inputFrameID && timestamp == other.timestamp; + } + + bool operator!=(const VRHMDSensorState& other) const { + return !(*this == other); + } + + void CalcViewMatrices(const gfx::Matrix4x4* aHeadToEyeTransforms); + +#endif // MOZILLA_INTERNAL_API +}; + +struct VRFieldOfView { + double upDegrees; + double rightDegrees; + double downDegrees; + double leftDegrees; + +#ifdef MOZILLA_INTERNAL_API + + VRFieldOfView() = default; + VRFieldOfView(double up, double right, double down, double left) + : upDegrees(up), + rightDegrees(right), + downDegrees(down), + leftDegrees(left) {} + + void SetFromTanRadians(double up, double right, double down, double left) { + upDegrees = atan(up) * 180.0 / M_PI; + rightDegrees = atan(right) * 180.0 / M_PI; + downDegrees = atan(down) * 180.0 / M_PI; + leftDegrees = atan(left) * 180.0 / M_PI; + } + + bool operator==(const VRFieldOfView& other) const { + return other.upDegrees == upDegrees && other.downDegrees == downDegrees && + other.rightDegrees == rightDegrees && + other.leftDegrees == leftDegrees; + } + + bool operator!=(const VRFieldOfView& other) const { + return !(*this == other); + } + + bool IsZero() const { + return upDegrees == 0.0 || rightDegrees == 0.0 || downDegrees == 0.0 || + leftDegrees == 0.0; + } + + Matrix4x4 ConstructProjectionMatrix(float zNear, float zFar, + bool rightHanded) const; + +#endif // MOZILLA_INTERNAL_API +}; + +struct VRDisplayState { + enum Eye { Eye_Left, Eye_Right, NumEyes }; + + // When true, indicates that the VR service has shut down + bool shutdown; + // Minimum number of milliseconds to wait before attempting + // to start the VR service again + uint32_t minRestartInterval; + char displayName[kVRDisplayNameMaxLen]; + // eight byte character code identifier + // LSB first, so "ABCDEFGH" -> ('H'<<56) + ('G'<<48) + ('F'<<40) + + // ('E'<<32) + ('D'<<24) + ('C'<<16) + + // ('B'<<8) + 'A'). + uint64_t eightCC; + VRDisplayCapabilityFlags capabilityFlags; + VRDisplayBlendMode blendMode; + VRFieldOfView eyeFOV[VRDisplayState::NumEyes]; + Point3D_POD eyeTranslation[VRDisplayState::NumEyes]; + IntSize_POD eyeResolution; + float nativeFramebufferScaleFactor; + bool suppressFrames; + bool isConnected; + bool isMounted; + FloatSize_POD stageSize; + // We can't use a Matrix4x4 here unless we ensure it's a POD type + float sittingToStandingTransform[16]; + uint64_t lastSubmittedFrameId; + bool lastSubmittedFrameSuccessful; + uint32_t presentingGeneration; + // Telemetry + bool reportsDroppedFrames; + uint64_t droppedFrameCount; + +#ifdef MOZILLA_INTERNAL_API + void Clear() { memset(this, 0, sizeof(VRDisplayState)); } +#endif +}; + +struct VRControllerState { + char controllerName[kVRControllerNameMaxLen]; +#ifdef MOZILLA_INTERNAL_API + dom::GamepadHand hand; +#else + ControllerHand hand; +#endif + // For WebXR->WebVR mapping conversion, once we remove WebVR, + // we can remove this item. + VRControllerType type; + // https://immersive-web.github.io/webxr/#enumdef-xrtargetraymode + TargetRayMode targetRayMode; + + // https://immersive-web.github.io/webxr-gamepads-module/#enumdef-gamepadmappingtype + GamepadMappingType mappingType; + + // Start frame ID of the most recent primary select + // action, or 0 if the select action has never occurred. + uint64_t selectActionStartFrameId; + // End frame Id of the most recent primary select + // action, or 0 if action never occurred. + // If selectActionStopFrameId is less than + // selectActionStartFrameId, then the select + // action has not ended yet. + uint64_t selectActionStopFrameId; + + // start frame Id of the most recent primary squeeze + // action, or 0 if the squeeze action has never occurred. + uint64_t squeezeActionStartFrameId; + // End frame Id of the most recent primary squeeze + // action, or 0 if action never occurred. + // If squeezeActionStopFrameId is less than + // squeezeActionStartFrameId, then the squeeze + // action has not ended yet. + uint64_t squeezeActionStopFrameId; + + uint32_t numButtons; + uint32_t numAxes; + uint32_t numHaptics; + // The current button pressed bit of button mask. + uint64_t buttonPressed; + // The current button touched bit of button mask. + uint64_t buttonTouched; + float triggerValue[kVRControllerMaxButtons]; + float axisValue[kVRControllerMaxAxis]; + +#ifdef MOZILLA_INTERNAL_API + dom::GamepadCapabilityFlags flags; +#else + ControllerCapabilityFlags flags; +#endif + + // When Cap_Position is set in flags, pose corresponds + // to the controllers' pose in grip space: + // https://immersive-web.github.io/webxr/#dom-xrinputsource-gripspace + VRPose pose; + + // When Cap_TargetRaySpacePosition is set in flags, targetRayPose corresponds + // to the controllers' pose in target ray space: + // https://immersive-web.github.io/webxr/#dom-xrinputsource-targetrayspace + VRPose targetRayPose; + + bool isPositionValid; + bool isOrientationValid; + +#ifdef MOZILLA_INTERNAL_API + void Clear() { memset(this, 0, sizeof(VRControllerState)); } +#endif +}; + +struct VRLayerEyeRect { + float x; + float y; + float width; + float height; +}; + +enum class VRLayerType : uint16_t { + LayerType_None = 0, + LayerType_2D_Content = 1, + LayerType_Stereo_Immersive = 2 +}; + +enum class VRLayerTextureType : uint16_t { + LayerTextureType_None = 0, + LayerTextureType_D3D10SurfaceDescriptor = 1, + LayerTextureType_MacIOSurface = 2, + LayerTextureType_GeckoSurfaceTexture = 3 +}; + +struct VRLayer_2D_Content { + VRLayerTextureHandle textureHandle; + VRLayerTextureType textureType; + uint64_t frameId; +}; + +struct VRLayer_Stereo_Immersive { + VRLayerTextureHandle textureHandle; + VRLayerTextureType textureType; + uint64_t frameId; + uint64_t inputFrameId; + VRLayerEyeRect leftEyeRect; + VRLayerEyeRect rightEyeRect; + IntSize_POD textureSize; +}; + +struct VRLayerState { + VRLayerType type; + union { + VRLayer_2D_Content layer_2d_content; + VRLayer_Stereo_Immersive layer_stereo_immersive; + }; +}; + +struct VRHapticState { + // Reference frame for timing. + // When 0, this does not represent an active haptic pulse. + uint64_t inputFrameID; + // Index within VRSystemState.controllerState identifying the controller + // to emit the haptic pulse + uint32_t controllerIndex; + // 0-based index indicating which haptic actuator within the controller + uint32_t hapticIndex; + // Start time of the haptic feedback pulse, relative to the start of + // inputFrameID, in seconds + float pulseStart; + // Duration of the haptic feedback pulse, in seconds + float pulseDuration; + // Intensity of the haptic feedback pulse, from 0.0f to 1.0f + float pulseIntensity; +}; + +struct VRBrowserState { +#if defined(__ANDROID__) + bool shutdown; +#endif // defined(__ANDROID__) + /** + * In order to support WebXR's navigator.xr.IsSessionSupported call without + * displaying any permission dialogue, it is necessary to have a safe way to + * detect the capability of running a VR or AR session without activating XR + * runtimes or powering on hardware. + * + * API's such as OpenVR make no guarantee that hardware and software won't be + * left activated after enumerating devices, so each backend in gfx/vr/service + * must allow for more granular detection of capabilities. + * + * When detectRuntimesOnly is true, the initialization exits early after + * reporting the presence of XR runtime software. + * + * The result of the runtime detection is reported with the Cap_ImmersiveVR + * and Cap_ImmersiveAR bits in VRDisplayState.flags. + */ + bool detectRuntimesOnly; + bool presentationActive; + bool navigationTransitionActive; + VRLayerState layerState[kVRLayerMaxCount]; + VRHapticState hapticState[kVRHapticsMaxCount]; + +#ifdef MOZILLA_INTERNAL_API + void Clear() { memset(this, 0, sizeof(VRBrowserState)); } +#endif +}; + +struct VRSystemState { + bool enumerationCompleted; + VRDisplayState displayState; + VRHMDSensorState sensorState; + VRControllerState controllerState[kVRControllerMaxCount]; +}; + +enum class VRFxEventType : uint8_t { + NONE = 0, + IME, + SHUTDOWN, + FULLSCREEN, + TOTAL +}; + +enum class VRFxEventState : uint8_t { + NONE = 0, + BLUR, + FOCUS, + FULLSCREEN_ENTER, + FULLSCREEN_EXIT, + TOTAL +}; + +// Data shared via shmem for running Firefox in a VR windowed environment +struct VRWindowState { + // State from Firefox + uint64_t hwndFx; + uint32_t widthFx; + uint32_t heightFx; + VRLayerTextureHandle textureFx; + uint32_t windowID; + VRFxEventType eventType; + VRFxEventState eventState; + + // State from VRHost + uint32_t dxgiAdapterHost; + uint32_t widthHost; + uint32_t heightHost; + + // Name of synchronization primitive to signal change to this struct + char signalName[32]; +}; + +enum class VRTelemetryId : uint8_t { + NONE = 0, + INSTALLED_FROM = 1, + ENTRY_METHOD = 2, + FIRST_RUN = 3, + TOTAL = 4, +}; + +enum class VRTelemetryInstallFrom : uint8_t { + User = 0, + FxR = 1, + HTC = 2, + Valve = 3, + TOTAL = 4, +}; + +enum class VRTelemetryEntryMethod : uint8_t { + SystemBtn = 0, + Library = 1, + Gaze = 2, + TOTAL = 3, +}; + +struct VRTelemetryState { + uint32_t uid; + + bool installedFrom : 1; + bool entryMethod : 1; + bool firstRun : 1; + + uint8_t installedFromValue : 3; + uint8_t entryMethodValue : 3; + bool firstRunValue : 1; +}; + +struct VRExternalShmem { + int32_t version; + int32_t size; +#if defined(__ANDROID__) + pthread_mutex_t systemMutex; + pthread_mutex_t geckoMutex; + pthread_mutex_t servoMutex; + pthread_cond_t systemCond; + pthread_cond_t geckoCond; + pthread_cond_t servoCond; +#else + int64_t generationA; +#endif // defined(__ANDROID__) + VRSystemState state; +#if !defined(__ANDROID__) + int64_t generationB; + int64_t geckoGenerationA; + int64_t servoGenerationA; +#endif // !defined(__ANDROID__) + VRBrowserState geckoState; + VRBrowserState servoState; +#if !defined(__ANDROID__) + int64_t geckoGenerationB; + int64_t servoGenerationB; +#endif // !defined(__ANDROID__) +#if defined(XP_WIN) + VRWindowState windowState; + VRTelemetryState telemetryState; +#endif +#ifdef MOZILLA_INTERNAL_API + void Clear() volatile { +/** + * When possible we do a memset_s, which is explicitly safe for + * the volatile, POD struct. A memset may be optimized out by + * the compiler and will fail to compile due to volatile keyword + * propagation. + * + * A loop-based fallback is provided in case the toolchain does + * not include STDC_LIB_EXT1 for memset_s. + */ +# ifdef __STDC_LIB_EXT1__ + memset_s((void*)this, sizeof(VRExternalShmem), 0, sizeof(VRExternalShmem)); +# else + size_t remaining = sizeof(VRExternalShmem); + volatile unsigned char* d = (volatile unsigned char*)this; + while (remaining--) { + *d++ = 0; + } +# endif + } +#endif +}; + +// As we are memcpy'ing VRExternalShmem and its members around, it must be a POD +// type +static_assert(std::is_pod<VRExternalShmem>::value, + "VRExternalShmem must be a POD type."); + +} // namespace gfx +} // namespace mozilla + +#endif /* GFX_VR_EXTERNAL_API_H */ |