Revision control
Copy as Markdown
/* -*- 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
#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
#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;
TargetRayMode targetRayMode;
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:
VRPose pose;
// When Cap_TargetRaySpacePosition is set in flags, targetRayPose corresponds
// to the controllers' pose in target ray space:
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 */