2014-07-09 23:24:49 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
* 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 "nsTArray.h"
|
2015-04-07 20:26:44 +03:00
|
|
|
#include "nsString.h"
|
2014-07-09 23:24:49 +04:00
|
|
|
#include "nsCOMPtr.h"
|
2015-10-18 08:24:48 +03:00
|
|
|
#include "mozilla/RefPtr.h"
|
2014-07-09 23:24:49 +04:00
|
|
|
#include "mozilla/gfx/2D.h"
|
2015-04-07 20:26:44 +03:00
|
|
|
#include "mozilla/Atomics.h"
|
2015-09-18 00:23:13 +03:00
|
|
|
#include "mozilla/EnumeratedArray.h"
|
|
|
|
#include "mozilla/TimeStamp.h"
|
|
|
|
#include "mozilla/TypedEnumBits.h"
|
2014-07-09 23:24:49 +04:00
|
|
|
|
|
|
|
namespace mozilla {
|
2015-07-02 18:58:24 +03:00
|
|
|
namespace layers {
|
2016-02-25 02:54:50 +03:00
|
|
|
class PTextureParent;
|
2015-07-02 18:58:24 +03:00
|
|
|
}
|
2016-10-24 13:09:11 +03:00
|
|
|
namespace dom {
|
2017-01-12 04:23:37 +03:00
|
|
|
enum class GamepadMappingType : uint8_t;
|
|
|
|
enum class GamepadHand : uint8_t;
|
2016-10-24 13:09:11 +03:00
|
|
|
struct GamepadPoseState;
|
|
|
|
}
|
2014-07-09 23:24:49 +04:00
|
|
|
namespace gfx {
|
2016-02-25 02:54:50 +03:00
|
|
|
class VRLayerParent;
|
|
|
|
class VRDisplayHost;
|
2016-10-07 11:58:01 +03:00
|
|
|
class VRControllerHost;
|
2014-07-09 23:24:49 +04:00
|
|
|
|
2016-10-04 11:22:42 +03:00
|
|
|
enum class VRDeviceType : uint16_t {
|
2014-07-09 23:24:49 +04:00
|
|
|
Oculus,
|
2016-07-22 22:41:00 +03:00
|
|
|
OpenVR,
|
2016-04-27 00:18:21 +03:00
|
|
|
OSVR,
|
2017-03-01 19:04:12 +03:00
|
|
|
Puppet,
|
2016-10-04 11:22:42 +03:00
|
|
|
NumVRDeviceTypes
|
2015-01-26 01:22:07 +03:00
|
|
|
};
|
2014-07-09 23:24:49 +04:00
|
|
|
|
2016-04-18 22:12:33 +03:00
|
|
|
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,
|
2016-07-22 22:41:00 +03:00
|
|
|
/**
|
|
|
|
* 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,
|
2016-10-19 01:18:10 +03:00
|
|
|
/**
|
|
|
|
* Cap_MountDetection is set if the VRDisplay is capable of sensing when the
|
|
|
|
* user is wearing the device.
|
|
|
|
*/
|
|
|
|
Cap_MountDetection = 1 << 8,
|
2016-04-18 22:12:33 +03:00
|
|
|
/**
|
|
|
|
* Cap_All used for validity checking during IPC serialization
|
|
|
|
*/
|
2016-10-19 01:18:10 +03:00
|
|
|
Cap_All = (1 << 9) - 1
|
2015-09-18 00:23:13 +03:00
|
|
|
};
|
2016-04-18 22:12:33 +03:00
|
|
|
|
|
|
|
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(VRDisplayCapabilityFlags)
|
2015-09-18 00:23:13 +03:00
|
|
|
|
2014-07-09 23:24:49 +04:00
|
|
|
struct VRFieldOfView {
|
|
|
|
VRFieldOfView() {}
|
|
|
|
VRFieldOfView(double up, double right, double down, double left)
|
|
|
|
: upDegrees(up), rightDegrees(right), downDegrees(down), leftDegrees(left)
|
|
|
|
{}
|
|
|
|
|
2016-07-22 22:41:00 +03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-07-09 23:24:49 +04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-10-01 02:43:33 +03:00
|
|
|
Matrix4x4 ConstructProjectionMatrix(float zNear, float zFar, bool rightHanded) const;
|
2015-07-02 18:58:24 +03:00
|
|
|
|
2014-07-09 23:24:49 +04:00
|
|
|
double upDegrees;
|
|
|
|
double rightDegrees;
|
|
|
|
double downDegrees;
|
|
|
|
double leftDegrees;
|
|
|
|
};
|
|
|
|
|
2017-05-09 02:01:36 +03:00
|
|
|
struct VRHMDSensorState {
|
|
|
|
VRHMDSensorState()
|
|
|
|
{
|
|
|
|
Clear();
|
|
|
|
}
|
|
|
|
int32_t inputFrameID;
|
|
|
|
double timestamp;
|
|
|
|
VRDisplayCapabilityFlags flags;
|
|
|
|
|
|
|
|
// These members will only change with inputFrameID:
|
|
|
|
float orientation[4];
|
|
|
|
float position[3];
|
|
|
|
float angularVelocity[3];
|
|
|
|
float angularAcceleration[3];
|
|
|
|
float linearVelocity[3];
|
|
|
|
float linearAcceleration[3];
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
2016-04-13 03:39:28 +03:00
|
|
|
struct VRDisplayInfo
|
2015-09-18 00:23:13 +03:00
|
|
|
{
|
2016-10-04 11:22:42 +03:00
|
|
|
VRDeviceType GetType() const { return mType; }
|
2016-02-25 02:54:50 +03:00
|
|
|
uint32_t GetDisplayID() const { return mDisplayID; }
|
|
|
|
const nsCString& GetDisplayName() const { return mDisplayName; }
|
2016-04-18 22:12:33 +03:00
|
|
|
VRDisplayCapabilityFlags GetCapabilities() const { return mCapabilityFlags; }
|
2014-07-09 23:24:49 +04:00
|
|
|
|
2015-09-18 00:23:13 +03:00
|
|
|
const IntSize& SuggestedEyeResolution() const { return mEyeResolution; }
|
|
|
|
const Point3D& GetEyeTranslation(uint32_t whichEye) const { return mEyeTranslation[whichEye]; }
|
|
|
|
const VRFieldOfView& GetEyeFOV(uint32_t whichEye) const { return mEyeFOV[whichEye]; }
|
2016-02-25 02:54:50 +03:00
|
|
|
bool GetIsConnected() const { return mIsConnected; }
|
2016-10-19 01:18:10 +03:00
|
|
|
bool GetIsMounted() const { return mIsMounted; }
|
2017-05-09 02:01:36 +03:00
|
|
|
uint32_t GetPresentingGroups() const { return mPresentingGroups; }
|
|
|
|
uint32_t GetGroupMask() const { return mGroupMask; }
|
2016-07-22 22:41:00 +03:00
|
|
|
const Size& GetStageSize() const { return mStageSize; }
|
|
|
|
const Matrix4x4& GetSittingToStandingTransform() const { return mSittingToStandingTransform; }
|
2017-05-09 02:01:36 +03:00
|
|
|
uint32_t GetFrameId() const { return mFrameId; }
|
2015-09-18 00:23:13 +03:00
|
|
|
|
|
|
|
enum Eye {
|
|
|
|
Eye_Left,
|
|
|
|
Eye_Right,
|
|
|
|
NumEyes
|
|
|
|
};
|
|
|
|
|
2016-02-25 02:54:50 +03:00
|
|
|
uint32_t mDisplayID;
|
2016-10-04 11:22:42 +03:00
|
|
|
VRDeviceType mType;
|
2016-02-25 02:54:50 +03:00
|
|
|
nsCString mDisplayName;
|
2016-04-18 22:12:33 +03:00
|
|
|
VRDisplayCapabilityFlags mCapabilityFlags;
|
2016-04-13 03:39:28 +03:00
|
|
|
VRFieldOfView mEyeFOV[VRDisplayInfo::NumEyes];
|
|
|
|
Point3D mEyeTranslation[VRDisplayInfo::NumEyes];
|
2015-09-18 00:23:13 +03:00
|
|
|
IntSize mEyeResolution;
|
2016-02-25 02:54:50 +03:00
|
|
|
bool mIsConnected;
|
2016-10-19 01:18:10 +03:00
|
|
|
bool mIsMounted;
|
2017-05-09 02:01:36 +03:00
|
|
|
uint32_t mPresentingGroups;
|
|
|
|
uint32_t mGroupMask;
|
2016-07-22 22:41:00 +03:00
|
|
|
Size mStageSize;
|
|
|
|
Matrix4x4 mSittingToStandingTransform;
|
2017-05-09 02:01:36 +03:00
|
|
|
uint32_t mFrameId;
|
|
|
|
VRHMDSensorState mLastSensorState[kVRMaxLatencyFrames];
|
2015-09-18 00:23:13 +03:00
|
|
|
|
2016-04-13 03:39:28 +03:00
|
|
|
bool operator==(const VRDisplayInfo& other) const {
|
2017-05-09 02:01:36 +03:00
|
|
|
for (size_t i = 0; i < kVRMaxLatencyFrames; i++) {
|
|
|
|
if (mLastSensorState[i] != other.mLastSensorState[i]) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2015-09-18 00:23:13 +03:00
|
|
|
return mType == other.mType &&
|
2016-02-25 02:54:50 +03:00
|
|
|
mDisplayID == other.mDisplayID &&
|
|
|
|
mDisplayName == other.mDisplayName &&
|
2016-04-18 22:12:33 +03:00
|
|
|
mCapabilityFlags == other.mCapabilityFlags &&
|
2015-09-18 00:23:13 +03:00
|
|
|
mEyeResolution == other.mEyeResolution &&
|
2016-02-25 02:54:50 +03:00
|
|
|
mIsConnected == other.mIsConnected &&
|
2016-10-19 01:18:10 +03:00
|
|
|
mIsMounted == other.mIsMounted &&
|
2017-05-09 02:01:36 +03:00
|
|
|
mPresentingGroups == other.mPresentingGroups &&
|
|
|
|
mGroupMask == other.mGroupMask &&
|
2015-09-18 00:23:13 +03:00
|
|
|
mEyeFOV[0] == other.mEyeFOV[0] &&
|
|
|
|
mEyeFOV[1] == other.mEyeFOV[1] &&
|
|
|
|
mEyeTranslation[0] == other.mEyeTranslation[0] &&
|
2016-07-22 22:41:00 +03:00
|
|
|
mEyeTranslation[1] == other.mEyeTranslation[1] &&
|
|
|
|
mStageSize == other.mStageSize &&
|
2017-05-09 02:01:36 +03:00
|
|
|
mSittingToStandingTransform == other.mSittingToStandingTransform &&
|
|
|
|
mFrameId == other.mFrameId;
|
2015-09-18 00:23:13 +03:00
|
|
|
}
|
|
|
|
|
2016-04-13 03:39:28 +03:00
|
|
|
bool operator!=(const VRDisplayInfo& other) const {
|
2015-09-18 00:23:13 +03:00
|
|
|
return !(*this == other);
|
|
|
|
}
|
2014-07-09 23:24:49 +04:00
|
|
|
|
2017-05-09 02:01:36 +03:00
|
|
|
const VRHMDSensorState& GetSensorState() const
|
2017-04-17 22:15:38 +03:00
|
|
|
{
|
2017-05-09 02:01:36 +03:00
|
|
|
return mLastSensorState[mFrameId % kVRMaxLatencyFrames];
|
2014-07-09 23:24:49 +04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-05-23 11:55:30 +03:00
|
|
|
struct VRSubmitFrameResultInfo
|
|
|
|
{
|
|
|
|
VRSubmitFrameResultInfo()
|
|
|
|
: mFrameNum(0),
|
|
|
|
mWidth(0),
|
|
|
|
mHeight(0)
|
|
|
|
{}
|
|
|
|
|
|
|
|
nsCString mBase64Image;
|
|
|
|
SurfaceFormat mFormat;
|
|
|
|
uint32_t mFrameNum;
|
|
|
|
uint32_t mWidth;
|
|
|
|
uint32_t mHeight;
|
|
|
|
};
|
|
|
|
|
2017-02-06 11:12:52 +03:00
|
|
|
struct VRControllerInfo
|
|
|
|
{
|
|
|
|
VRDeviceType GetType() const { return mType; }
|
|
|
|
uint32_t GetControllerID() const { return mControllerID; }
|
|
|
|
const nsCString& GetControllerName() const { return mControllerName; }
|
|
|
|
dom::GamepadMappingType GetMappingType() const { return mMappingType; }
|
2017-07-14 12:01:09 +03:00
|
|
|
uint32_t GetDisplayID() const { return mDisplayID; }
|
2017-02-06 11:12:52 +03:00
|
|
|
dom::GamepadHand GetHand() const { return mHand; }
|
|
|
|
uint32_t GetNumButtons() const { return mNumButtons; }
|
|
|
|
uint32_t GetNumAxes() const { return mNumAxes; }
|
2017-02-02 09:57:58 +03:00
|
|
|
uint32_t GetNumHaptics() const { return mNumHaptics; }
|
2017-02-06 11:12:52 +03:00
|
|
|
|
|
|
|
uint32_t mControllerID;
|
|
|
|
VRDeviceType mType;
|
|
|
|
nsCString mControllerName;
|
|
|
|
dom::GamepadMappingType mMappingType;
|
2017-07-14 12:01:09 +03:00
|
|
|
uint32_t mDisplayID;
|
2017-02-06 11:12:52 +03:00
|
|
|
dom::GamepadHand mHand;
|
|
|
|
uint32_t mNumButtons;
|
|
|
|
uint32_t mNumAxes;
|
2017-02-02 09:57:58 +03:00
|
|
|
uint32_t mNumHaptics;
|
2017-02-06 11:12:52 +03:00
|
|
|
|
|
|
|
bool operator==(const VRControllerInfo& other) const {
|
|
|
|
return mType == other.mType &&
|
|
|
|
mControllerID == other.mControllerID &&
|
|
|
|
mControllerName == other.mControllerName &&
|
|
|
|
mMappingType == other.mMappingType &&
|
2017-07-14 12:01:09 +03:00
|
|
|
mDisplayID == other.mDisplayID &&
|
2017-02-06 11:12:52 +03:00
|
|
|
mHand == other.mHand &&
|
|
|
|
mNumButtons == other.mNumButtons &&
|
2017-02-02 09:57:58 +03:00
|
|
|
mNumAxes == other.mNumAxes &&
|
|
|
|
mNumHaptics == other.mNumHaptics;
|
2017-02-06 11:12:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=(const VRControllerInfo& other) const {
|
|
|
|
return !(*this == other);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-08-28 13:43:25 +03:00
|
|
|
struct VRTelemetry
|
|
|
|
{
|
|
|
|
VRTelemetry()
|
|
|
|
: mLastDroppedFrameCount(-1)
|
|
|
|
{}
|
|
|
|
|
|
|
|
void Clear() {
|
|
|
|
mPresentationStart = TimeStamp();
|
|
|
|
mLastDroppedFrameCount = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsLastDroppedFrameValid() {
|
|
|
|
return (mLastDroppedFrameCount != -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
TimeStamp mPresentationStart;
|
|
|
|
int32_t mLastDroppedFrameCount;
|
|
|
|
};
|
|
|
|
|
2017-01-24 12:49:11 +03:00
|
|
|
class VRSystemManager {
|
2015-07-02 18:58:24 +03:00
|
|
|
public:
|
2016-02-25 02:54:50 +03:00
|
|
|
static uint32_t AllocateDisplayID();
|
2017-07-14 12:01:09 +03:00
|
|
|
static uint32_t AllocateControllerID();
|
2015-07-02 18:58:24 +03:00
|
|
|
|
|
|
|
protected:
|
2016-02-25 02:54:50 +03:00
|
|
|
static Atomic<uint32_t> sDisplayBase;
|
2017-07-14 12:01:09 +03:00
|
|
|
static Atomic<uint32_t> sControllerBase;
|
2015-09-18 00:23:13 +03:00
|
|
|
|
2015-04-01 23:02:20 +03:00
|
|
|
public:
|
2017-01-24 12:49:11 +03:00
|
|
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRSystemManager)
|
2015-04-01 23:02:20 +03:00
|
|
|
|
|
|
|
virtual void Destroy() = 0;
|
2017-03-30 16:35:49 +03:00
|
|
|
virtual void Shutdown() = 0;
|
2017-07-04 23:28:27 +03:00
|
|
|
virtual bool GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult) = 0;
|
2017-03-22 04:58:06 +03:00
|
|
|
virtual bool GetIsPresenting() = 0;
|
2017-01-24 12:49:11 +03:00
|
|
|
virtual void HandleInput() = 0;
|
|
|
|
virtual void GetControllers(nsTArray<RefPtr<VRControllerHost>>& aControllerResult) = 0;
|
|
|
|
virtual void ScanForControllers() = 0;
|
|
|
|
virtual void RemoveControllers() = 0;
|
2017-02-02 09:57:58 +03:00
|
|
|
virtual void VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
|
|
|
|
double aIntensity, double aDuration, uint32_t aPromiseID) = 0;
|
|
|
|
virtual void StopVibrateHaptic(uint32_t aControllerIdx) = 0;
|
2017-04-06 14:00:20 +03:00
|
|
|
void NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed, bool aTouched,
|
|
|
|
double aValue);
|
2017-01-24 12:49:11 +03:00
|
|
|
void NewAxisMove(uint32_t aIndex, uint32_t aAxis, double aValue);
|
|
|
|
void NewPoseState(uint32_t aIndex, const dom::GamepadPoseState& aPose);
|
2017-04-18 10:58:34 +03:00
|
|
|
void NewHandChangeEvent(uint32_t aIndex, const dom::GamepadHand aHand);
|
2017-02-06 11:12:52 +03:00
|
|
|
void AddGamepad(const VRControllerInfo& controllerInfo);
|
2017-01-24 12:49:11 +03:00
|
|
|
void RemoveGamepad(uint32_t aIndex);
|
2015-04-01 23:02:20 +03:00
|
|
|
|
|
|
|
protected:
|
2017-01-24 12:49:11 +03:00
|
|
|
VRSystemManager() : mControllerCount(0) { }
|
|
|
|
virtual ~VRSystemManager() { }
|
|
|
|
|
|
|
|
uint32_t mControllerCount;
|
2014-07-09 23:24:49 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace gfx
|
|
|
|
} // namespace mozilla
|
|
|
|
|
|
|
|
#endif /* GFX_VR_H */
|