--- a/gfx/moz.build
+++ b/gfx/moz.build
@@ -18,16 +18,17 @@ DIRS += [
'qcms',
'gl',
'layers',
'graphite2/src',
'harfbuzz/src',
'ots/src',
'thebes',
'ipc',
+ 'vr',
]
if CONFIG['MOZ_ENABLE_SKIA']:
DIRS += ['skia']
if CONFIG['ENABLE_TESTS']:
DIRS += ['tests/gtest']
deleted file mode 100644
--- a/gfx/thebes/gfxVR.cpp
+++ /dev/null
@@ -1,658 +0,0 @@
-/* -*- 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/. */
-
-#include <math.h>
-
-#include "prlink.h"
-#include "prmem.h"
-#include "prenv.h"
-#include "gfxPrefs.h"
-#include "gfxVR.h"
-#include "nsString.h"
-#include "mozilla/Preferences.h"
-
-#include "ovr_capi_dynamic.h"
-
-#include "nsServiceManagerUtils.h"
-#include "nsIScreenManager.h"
-
-#ifdef XP_WIN
-#include "gfxWindowsPlatform.h" // for gfxWindowsPlatform::GetDPIScale
-#endif
-
-#ifndef M_PI
-# define M_PI 3.14159265358979323846
-#endif
-
-namespace {
-
-#ifdef OVR_CAPI_LIMITED_MOZILLA
-static pfn_ovr_Initialize ovr_Initialize = nullptr;
-static pfn_ovr_Shutdown ovr_Shutdown = nullptr;
-static pfn_ovrHmd_Detect ovrHmd_Detect = nullptr;
-static pfn_ovrHmd_Create ovrHmd_Create = nullptr;
-static pfn_ovrHmd_Destroy ovrHmd_Destroy = nullptr;
-static pfn_ovrHmd_CreateDebug ovrHmd_CreateDebug = nullptr;
-static pfn_ovrHmd_GetLastError ovrHmd_GetLastError = nullptr;
-static pfn_ovrHmd_AttachToWindow ovrHmd_AttachToWindow = nullptr;
-static pfn_ovrHmd_GetEnabledCaps ovrHmd_GetEnabledCaps = nullptr;
-static pfn_ovrHmd_SetEnabledCaps ovrHmd_SetEnabledCaps = nullptr;
-static pfn_ovrHmd_ConfigureTracking ovrHmd_ConfigureTracking = nullptr;
-static pfn_ovrHmd_RecenterPose ovrHmd_RecenterPose = nullptr;
-static pfn_ovrHmd_GetTrackingState ovrHmd_GetTrackingState = nullptr;
-static pfn_ovrHmd_GetFovTextureSize ovrHmd_GetFovTextureSize = nullptr;
-static pfn_ovrHmd_GetRenderDesc ovrHmd_GetRenderDesc = nullptr;
-static pfn_ovrHmd_CreateDistortionMesh ovrHmd_CreateDistortionMesh = nullptr;
-static pfn_ovrHmd_DestroyDistortionMesh ovrHmd_DestroyDistortionMesh = nullptr;
-static pfn_ovrHmd_GetRenderScaleAndOffset ovrHmd_GetRenderScaleAndOffset = nullptr;
-static pfn_ovrHmd_GetFrameTiming ovrHmd_GetFrameTiming = nullptr;
-static pfn_ovrHmd_BeginFrameTiming ovrHmd_BeginFrameTiming = nullptr;
-static pfn_ovrHmd_EndFrameTiming ovrHmd_EndFrameTiming = nullptr;
-static pfn_ovrHmd_ResetFrameTiming ovrHmd_ResetFrameTiming = nullptr;
-static pfn_ovrHmd_GetEyePoses ovrHmd_GetEyePoses = nullptr;
-static pfn_ovrHmd_GetHmdPosePerEye ovrHmd_GetHmdPosePerEye = nullptr;
-static pfn_ovrHmd_GetEyeTimewarpMatrices ovrHmd_GetEyeTimewarpMatrices = nullptr;
-static pfn_ovrMatrix4f_Projection ovrMatrix4f_Projection = nullptr;
-static pfn_ovrMatrix4f_OrthoSubProjection ovrMatrix4f_OrthoSubProjection = nullptr;
-static pfn_ovr_GetTimeInSeconds ovr_GetTimeInSeconds = nullptr;
-
-#if defined(XP_WIN)
-# ifdef HAVE_64BIT_BUILD
-# define OVR_LIB_NAME "libovr64.dll"
-# else
-# define OVR_LIB_NAME "libovr.dll"
-# endif
-#elif defined(XP_MACOSX)
-# define OVR_LIB_NAME "libovr.dylib"
-#else
-# define OVR_LIB_NAME 0
-#endif
-
-static bool
-InitializeOculusCAPI()
-{
- static PRLibrary *ovrlib = nullptr;
-
- if (!ovrlib) {
- const char *libName = OVR_LIB_NAME;
-
- // If the pref is present, we override libName
- nsAdoptingCString prefLibName = mozilla::Preferences::GetCString("dom.vr.ovr_lib_path");
- if (prefLibName && prefLibName.get()) {
- libName = prefLibName.get();
- }
-
- // If the env var is present, we override libName
- if (PR_GetEnv("OVR_LIB_NAME")) {
- libName = PR_GetEnv("OVR_LIB_NAME");
- }
-
- if (!libName) {
- printf_stderr("Don't know how to find Oculus VR library; missing dom.vr.ovr_lib_path or OVR_LIB_NAME\n");
- return false;
- }
-
- ovrlib = PR_LoadLibrary(libName);
-
- if (!ovrlib) {
- // Not found? Try harder. Needed mainly on OSX/etc. where
- // the binary location is not in the search path.
- const char *xulName = "libxul.so";
-#if defined(XP_MACOSX)
- xulName = "XUL";
-#endif
-
- char *xulpath = PR_GetLibraryFilePathname(xulName, (PRFuncPtr) &InitializeOculusCAPI);
- if (xulpath) {
- char *xuldir = strrchr(xulpath, '/');
- if (xuldir) {
- *xuldir = 0;
- xuldir = xulpath;
-
- char *ovrpath = PR_GetLibraryName(xuldir, libName);
- ovrlib = PR_LoadLibrary(ovrpath);
- PR_Free(ovrpath);
- }
- PR_Free(xulpath);
- }
- }
-
- if (!ovrlib) {
- printf_stderr("Failed to load Oculus VR library, tried '%s'\n", libName);
- return false;
- }
- }
-
- // was it already initialized?
- if (ovr_Initialize)
- return true;
-
-#define REQUIRE_FUNCTION(_x) do { \
- *(void **)&_x = (void *) PR_FindSymbol(ovrlib, #_x); \
- if (!_x) { printf_stderr(#_x " symbol missing\n"); goto fail; } \
- } while (0)
-
- REQUIRE_FUNCTION(ovr_Initialize);
- REQUIRE_FUNCTION(ovr_Shutdown);
- REQUIRE_FUNCTION(ovrHmd_Detect);
- REQUIRE_FUNCTION(ovrHmd_Create);
- REQUIRE_FUNCTION(ovrHmd_Destroy);
- REQUIRE_FUNCTION(ovrHmd_CreateDebug);
- REQUIRE_FUNCTION(ovrHmd_GetLastError);
- REQUIRE_FUNCTION(ovrHmd_AttachToWindow);
- REQUIRE_FUNCTION(ovrHmd_GetEnabledCaps);
- REQUIRE_FUNCTION(ovrHmd_SetEnabledCaps);
- REQUIRE_FUNCTION(ovrHmd_ConfigureTracking);
- REQUIRE_FUNCTION(ovrHmd_RecenterPose);
- REQUIRE_FUNCTION(ovrHmd_GetTrackingState);
-
- REQUIRE_FUNCTION(ovrHmd_GetFovTextureSize);
- REQUIRE_FUNCTION(ovrHmd_GetRenderDesc);
- REQUIRE_FUNCTION(ovrHmd_CreateDistortionMesh);
- REQUIRE_FUNCTION(ovrHmd_DestroyDistortionMesh);
- REQUIRE_FUNCTION(ovrHmd_GetRenderScaleAndOffset);
- REQUIRE_FUNCTION(ovrHmd_GetFrameTiming);
- REQUIRE_FUNCTION(ovrHmd_BeginFrameTiming);
- REQUIRE_FUNCTION(ovrHmd_EndFrameTiming);
- REQUIRE_FUNCTION(ovrHmd_ResetFrameTiming);
- REQUIRE_FUNCTION(ovrHmd_GetEyePoses);
- REQUIRE_FUNCTION(ovrHmd_GetHmdPosePerEye);
- REQUIRE_FUNCTION(ovrHmd_GetEyeTimewarpMatrices);
- REQUIRE_FUNCTION(ovrMatrix4f_Projection);
- REQUIRE_FUNCTION(ovrMatrix4f_OrthoSubProjection);
- REQUIRE_FUNCTION(ovr_GetTimeInSeconds);
-
-#undef REQUIRE_FUNCTION
-
- return true;
-
- fail:
- ovr_Initialize = nullptr;
- return false;
-}
-
-#else
-// we're statically linked; it's available
-static bool InitializeOculusCAPI()
-{
- return true;
-}
-#endif
-
-} // anonymous namespace
-
-using namespace mozilla::gfx;
-
-// Dummy nsIScreen implementation, for when we just need to specify a size
-class FakeScreen : public nsIScreen
-{
-public:
- explicit FakeScreen(const IntRect& aScreenRect)
- : mScreenRect(aScreenRect)
- { }
-
- NS_DECL_ISUPPORTS
-
- NS_IMETHOD GetRect(int32_t *l, int32_t *t, int32_t *w, int32_t *h) override {
- *l = mScreenRect.x;
- *t = mScreenRect.y;
- *w = mScreenRect.width;
- *h = mScreenRect.height;
- return NS_OK;
- }
- NS_IMETHOD GetAvailRect(int32_t *l, int32_t *t, int32_t *w, int32_t *h) override {
- return GetRect(l, t, w, h);
- }
- NS_IMETHOD GetRectDisplayPix(int32_t *l, int32_t *t, int32_t *w, int32_t *h) override {
- return GetRect(l, t, w, h);
- }
- NS_IMETHOD GetAvailRectDisplayPix(int32_t *l, int32_t *t, int32_t *w, int32_t *h) override {
- return GetAvailRect(l, t, w, h);
- }
-
- NS_IMETHOD GetId(uint32_t* aId) override { *aId = (uint32_t)-1; return NS_OK; }
- NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth) override { *aPixelDepth = 24; return NS_OK; }
- NS_IMETHOD GetColorDepth(int32_t* aColorDepth) override { *aColorDepth = 24; return NS_OK; }
-
- NS_IMETHOD LockMinimumBrightness(uint32_t aBrightness) override { return NS_ERROR_NOT_AVAILABLE; }
- NS_IMETHOD UnlockMinimumBrightness(uint32_t aBrightness) override { return NS_ERROR_NOT_AVAILABLE; }
- NS_IMETHOD GetRotation(uint32_t* aRotation) override {
- *aRotation = nsIScreen::ROTATION_0_DEG;
- return NS_OK;
- }
- NS_IMETHOD SetRotation(uint32_t aRotation) override { return NS_ERROR_NOT_AVAILABLE; }
- NS_IMETHOD GetContentsScaleFactor(double* aContentsScaleFactor) override {
- *aContentsScaleFactor = 1.0;
- return NS_OK;
- }
-
-protected:
- virtual ~FakeScreen() {}
-
- IntRect mScreenRect;
-};
-
-NS_IMPL_ISUPPORTS(FakeScreen, nsIScreen)
-
-class HMDInfoOculus : public VRHMDInfo {
- friend class VRHMDManagerOculusImpl;
-public:
- explicit HMDInfoOculus(ovrHmd aHMD);
-
- bool SetFOV(const VRFieldOfView& aFOVLeft, const VRFieldOfView& aFOVRight,
- double zNear, double zFar) override;
-
- bool StartSensorTracking() override;
- VRHMDSensorState GetSensorState(double timeOffset) override;
- void StopSensorTracking() override;
- void ZeroSensor() override;
-
- void FillDistortionConstants(uint32_t whichEye,
- const IntSize& textureSize, const IntRect& eyeViewport,
- const Size& destViewport, const Rect& destRect,
- VRDistortionConstants& values) override;
-
- void Destroy();
-
-protected:
- virtual ~HMDInfoOculus() {
- Destroy();
- MOZ_COUNT_DTOR_INHERITED(HMDInfoOculus, VRHMDInfo);
- }
-
- ovrHmd mHMD;
- ovrFovPort mFOVPort[2];
- uint32_t mStartCount;
-};
-
-static ovrFovPort
-ToFovPort(const VRFieldOfView& aFOV)
-{
- ovrFovPort fovPort;
- fovPort.LeftTan = tan(aFOV.leftDegrees * M_PI / 180.0);
- fovPort.RightTan = tan(aFOV.rightDegrees * M_PI / 180.0);
- fovPort.UpTan = tan(aFOV.upDegrees * M_PI / 180.0);
- fovPort.DownTan = tan(aFOV.downDegrees * M_PI / 180.0);
- return fovPort;
-}
-
-static VRFieldOfView
-FromFovPort(const ovrFovPort& aFOV)
-{
- VRFieldOfView fovInfo;
- fovInfo.leftDegrees = atan(aFOV.LeftTan) * 180.0 / M_PI;
- fovInfo.rightDegrees = atan(aFOV.RightTan) * 180.0 / M_PI;
- fovInfo.upDegrees = atan(aFOV.UpTan) * 180.0 / M_PI;
- fovInfo.downDegrees = atan(aFOV.DownTan) * 180.0 / M_PI;
- return fovInfo;
-}
-
-HMDInfoOculus::HMDInfoOculus(ovrHmd aHMD)
- : VRHMDInfo(VRHMDType::Oculus)
- , mHMD(aHMD)
- , mStartCount(0)
-{
- MOZ_COUNT_CTOR_INHERITED(HMDInfoOculus, VRHMDInfo);
-
- mSupportedSensorBits = 0;
- if (mHMD->TrackingCaps & ovrTrackingCap_Orientation)
- mSupportedSensorBits |= State_Orientation;
- if (mHMD->TrackingCaps & ovrTrackingCap_Position)
- mSupportedSensorBits |= State_Position;
-
- mRecommendedEyeFOV[Eye_Left] = FromFovPort(mHMD->DefaultEyeFov[ovrEye_Left]);
- mRecommendedEyeFOV[Eye_Right] = FromFovPort(mHMD->DefaultEyeFov[ovrEye_Right]);
-
- mMaximumEyeFOV[Eye_Left] = FromFovPort(mHMD->MaxEyeFov[ovrEye_Left]);
- mMaximumEyeFOV[Eye_Right] = FromFovPort(mHMD->MaxEyeFov[ovrEye_Right]);
-
- SetFOV(mRecommendedEyeFOV[Eye_Left], mRecommendedEyeFOV[Eye_Right], 0.01, 10000.0);
-
- nsCOMPtr<nsIScreenManager> screenmgr = do_GetService("@mozilla.org/gfx/screenmanager;1");
- if (screenmgr) {
- screenmgr->ScreenForRect(mHMD->WindowsPos.x, mHMD->WindowsPos.y,
- mHMD->Resolution.w, mHMD->Resolution.h,
- getter_AddRefs(mScreen));
- }
-}
-
-void
-HMDInfoOculus::Destroy()
-{
- if (mHMD) {
- ovrHmd_Destroy(mHMD);
- mHMD = nullptr;
- }
-}
-
-bool
-HMDInfoOculus::SetFOV(const VRFieldOfView& aFOVLeft, const VRFieldOfView& aFOVRight,
- double zNear, double zFar)
-{
- float pixelsPerDisplayPixel = 1.0;
- ovrSizei texSize[2];
-
- uint32_t caps = ovrDistortionCap_Chromatic | ovrDistortionCap_Vignette; // XXX TODO add TimeWarp
-
- // get eye parameters and create the mesh
- for (uint32_t eye = 0; eye < NumEyes; eye++) {
- mEyeFOV[eye] = eye == 0 ? aFOVLeft : aFOVRight;
- mFOVPort[eye] = ToFovPort(mEyeFOV[eye]);
-
- ovrEyeRenderDesc renderDesc = ovrHmd_GetRenderDesc(mHMD, (ovrEyeType) eye, mFOVPort[eye]);
-
- // these values are negated so that content can add the adjustment to its camera position,
- // instead of subtracting
- mEyeTranslation[eye] = Point3D(-renderDesc.ViewAdjust.x, -renderDesc.ViewAdjust.y, -renderDesc.ViewAdjust.z);
-
- // note that we are using a right-handed coordinate system here, to match CSS
- ovrMatrix4f projMatrix = ovrMatrix4f_Projection(mFOVPort[eye], zNear, zFar, true);
-
- // XXX this is gross, we really need better methods on Matrix4x4
- memcpy(&mEyeProjectionMatrix[eye], projMatrix.M, sizeof(ovrMatrix4f));
- mEyeProjectionMatrix[eye].Transpose();
-
- texSize[eye] = ovrHmd_GetFovTextureSize(mHMD, (ovrEyeType) eye, mFOVPort[eye], pixelsPerDisplayPixel);
-
- ovrDistortionMesh mesh;
- bool ok = ovrHmd_CreateDistortionMesh(mHMD, (ovrEyeType) eye, mFOVPort[eye], caps, &mesh);
- if (!ok)
- return false;
-
- mDistortionMesh[eye].mVertices.SetLength(mesh.VertexCount);
- mDistortionMesh[eye].mIndices.SetLength(mesh.IndexCount);
-
- ovrDistortionVertex *srcv = mesh.pVertexData;
- VRDistortionVertex *destv = mDistortionMesh[eye].mVertices.Elements();
- memset(destv, 0, mesh.VertexCount * sizeof(VRDistortionVertex));
- for (uint32_t i = 0; i < mesh.VertexCount; ++i) {
- destv[i].pos[0] = srcv[i].ScreenPosNDC.x;
- destv[i].pos[1] = srcv[i].ScreenPosNDC.y;
-
- destv[i].texR[0] = srcv[i].TanEyeAnglesR.x;
- destv[i].texR[1] = srcv[i].TanEyeAnglesR.y;
- destv[i].texG[0] = srcv[i].TanEyeAnglesG.x;
- destv[i].texG[1] = srcv[i].TanEyeAnglesG.y;
- destv[i].texB[0] = srcv[i].TanEyeAnglesB.x;
- destv[i].texB[1] = srcv[i].TanEyeAnglesB.y;
-
- destv[i].genericAttribs[0] = srcv[i].VignetteFactor;
- destv[i].genericAttribs[1] = srcv[i].TimeWarpFactor;
- }
-
- memcpy(mDistortionMesh[eye].mIndices.Elements(), mesh.pIndexData, mesh.IndexCount * sizeof(uint16_t));
- ovrHmd_DestroyDistortionMesh(&mesh);
- }
-
- // take the max of both for eye resolution
- mEyeResolution.width = std::max(texSize[Eye_Left].w, texSize[Eye_Right].w);
- mEyeResolution.height = std::max(texSize[Eye_Left].h, texSize[Eye_Right].h);
-
- mConfiguration.hmdType = mType;
- mConfiguration.value = 0;
- mConfiguration.fov[0] = aFOVLeft;
- mConfiguration.fov[1] = aFOVRight;
-
- return true;
- //* need to call this during rendering each frame I think? */
- //ovrHmd_GetRenderScaleAndOffset(fovPort, texSize, renderViewport, uvScaleOffsetOut);
-}
-
-void
-HMDInfoOculus::FillDistortionConstants(uint32_t whichEye,
- const IntSize& textureSize,
- const IntRect& eyeViewport,
- const Size& destViewport,
- const Rect& destRect,
- VRDistortionConstants& values)
-{
- ovrSizei texSize = { textureSize.width, textureSize.height };
- ovrRecti eyePort = { { eyeViewport.x, eyeViewport.y }, { eyeViewport.width, eyeViewport.height } };
- ovrVector2f scaleOut[2];
-
- ovrHmd_GetRenderScaleAndOffset(mFOVPort[whichEye], texSize, eyePort, scaleOut);
-
- values.eyeToSourceScaleAndOffset[0] = scaleOut[0].x;
- values.eyeToSourceScaleAndOffset[1] = scaleOut[0].y;
- values.eyeToSourceScaleAndOffset[2] = scaleOut[1].x;
- values.eyeToSourceScaleAndOffset[3] = scaleOut[1].y;
-
- // These values are in clip space [-1..1] range, but we're providing
- // scaling in the 0..2 space for sanity.
-
- // this is the destRect in clip space
- float x0 = destRect.x / destViewport.width * 2.0 - 1.0;
- float x1 = (destRect.x + destRect.width) / destViewport.width * 2.0 - 1.0;
-
- float y0 = destRect.y / destViewport.height * 2.0 - 1.0;
- float y1 = (destRect.y + destRect.height) / destViewport.height * 2.0 - 1.0;
-
- // offset
- values.destinationScaleAndOffset[0] = (x0+x1) / 2.0;
- values.destinationScaleAndOffset[1] = (y0+y1) / 2.0;
- // scale
- values.destinationScaleAndOffset[2] = destRect.width / destViewport.width;
- values.destinationScaleAndOffset[3] = destRect.height / destViewport.height;
-}
-
-bool
-HMDInfoOculus::StartSensorTracking()
-{
- if (mStartCount == 0) {
- bool ok = ovrHmd_ConfigureTracking(mHMD, ovrTrackingCap_Orientation | ovrTrackingCap_Position, 0);
- if (!ok)
- return false;
- }
-
- mStartCount++;
- return true;
-}
-
-void
-HMDInfoOculus::StopSensorTracking()
-{
- if (--mStartCount == 0) {
- ovrHmd_ConfigureTracking(mHMD, 0, 0);
- }
-}
-
-void
-HMDInfoOculus::ZeroSensor()
-{
- ovrHmd_RecenterPose(mHMD);
-}
-
-VRHMDSensorState
-HMDInfoOculus::GetSensorState(double timeOffset)
-{
- VRHMDSensorState result;
- result.Clear();
-
- // XXX this is the wrong time base for timeOffset; we need to figure out how to synchronize
- // the Oculus time base and the browser one.
- ovrTrackingState state = ovrHmd_GetTrackingState(mHMD, ovr_GetTimeInSeconds() + timeOffset);
- ovrPoseStatef& pose(state.HeadPose);
-
- result.timestamp = pose.TimeInSeconds;
-
- if (state.StatusFlags & ovrStatus_OrientationTracked) {
- result.flags |= State_Orientation;
-
- result.orientation[0] = pose.ThePose.Orientation.x;
- result.orientation[1] = pose.ThePose.Orientation.y;
- result.orientation[2] = pose.ThePose.Orientation.z;
- result.orientation[3] = pose.ThePose.Orientation.w;
-
- result.angularVelocity[0] = pose.AngularVelocity.x;
- result.angularVelocity[1] = pose.AngularVelocity.y;
- result.angularVelocity[2] = pose.AngularVelocity.z;
-
- result.angularAcceleration[0] = pose.AngularAcceleration.x;
- result.angularAcceleration[1] = pose.AngularAcceleration.y;
- result.angularAcceleration[2] = pose.AngularAcceleration.z;
- }
-
- if (state.StatusFlags & ovrStatus_PositionTracked) {
- result.flags |= State_Position;
-
- result.position[0] = pose.ThePose.Position.x;
- result.position[1] = pose.ThePose.Position.y;
- result.position[2] = pose.ThePose.Position.z;
-
- result.linearVelocity[0] = pose.LinearVelocity.x;
- result.linearVelocity[1] = pose.LinearVelocity.y;
- result.linearVelocity[2] = pose.LinearVelocity.z;
-
- result.linearAcceleration[0] = pose.LinearAcceleration.x;
- result.linearAcceleration[1] = pose.LinearAcceleration.y;
- result.linearAcceleration[2] = pose.LinearAcceleration.z;
- }
-
- return result;
-}
-
-namespace mozilla {
-namespace gfx {
-
-class VRHMDManagerOculusImpl {
-public:
- VRHMDManagerOculusImpl() : mOculusInitialized(false), mOculusPlatformInitialized(false)
- { }
-
- bool PlatformInit();
- bool Init();
- void Destroy();
- void GetOculusHMDs(nsTArray<nsRefPtr<VRHMDInfo> >& aHMDResult);
-protected:
- nsTArray<nsRefPtr<HMDInfoOculus>> mOculusHMDs;
- bool mOculusInitialized;
- bool mOculusPlatformInitialized;
-};
-
-} // namespace gfx
-} // namespace mozilla
-
-VRHMDManagerOculusImpl *VRHMDManagerOculus::mImpl = nullptr;
-
-// These just forward to the Impl class, to have a non-static container for various
-// objects.
-
-bool
-VRHMDManagerOculus::PlatformInit()
-{
- if (!mImpl) {
- mImpl = new VRHMDManagerOculusImpl;
- }
- return mImpl->PlatformInit();
-}
-
-bool
-VRHMDManagerOculus::Init()
-{
- if (!mImpl) {
- mImpl = new VRHMDManagerOculusImpl;
- }
- return mImpl->Init();
-}
-
-void
-VRHMDManagerOculus::GetOculusHMDs(nsTArray<nsRefPtr<VRHMDInfo>>& aHMDResult)
-{
- if (!mImpl) {
- mImpl = new VRHMDManagerOculusImpl;
- }
- mImpl->GetOculusHMDs(aHMDResult);
-}
-
-void
-VRHMDManagerOculus::Destroy()
-{
- if (!mImpl)
- return;
- mImpl->Destroy();
- delete mImpl;
- mImpl = nullptr;
-}
-
-bool
-VRHMDManagerOculusImpl::PlatformInit()
-{
- if (mOculusPlatformInitialized)
- return true;
-
- if (!gfxPrefs::VREnabled())
- return false;
-
- if (!InitializeOculusCAPI())
- return false;
-
- bool ok = ovr_Initialize();
-
- if (!ok)
- return false;
-
- mOculusPlatformInitialized = true;
- return true;
-}
-
-bool
-VRHMDManagerOculusImpl::Init()
-{
- if (mOculusInitialized)
- return true;
-
- if (!PlatformInit())
- return false;
-
- int count = ovrHmd_Detect();
-
- for (int i = 0; i < count; ++i) {
- ovrHmd hmd = ovrHmd_Create(i);
- if (!hmd)
- continue;
- nsRefPtr<HMDInfoOculus> oc = new HMDInfoOculus(hmd);
- mOculusHMDs.AppendElement(oc);
- }
-
- // VRAddTestDevices == 1: add test device only if no real devices present
- // VRAddTestDevices == 2: add test device always
- if ((count == 0 && gfxPrefs::VRAddTestDevices() == 1) ||
- (gfxPrefs::VRAddTestDevices() == 2))
- {
- ovrHmd hmd = ovrHmd_CreateDebug(ovrHmd_DK2);
- if (hmd) {
- nsRefPtr<HMDInfoOculus> oc = new HMDInfoOculus(hmd);
- mOculusHMDs.AppendElement(oc);
- }
- }
-
- mOculusInitialized = true;
- return true;
-}
-
-void
-VRHMDManagerOculusImpl::Destroy()
-{
- if (!mOculusInitialized)
- return;
-
- for (size_t i = 0; i < mOculusHMDs.Length(); ++i) {
- mOculusHMDs[i]->Destroy();
- }
-
- mOculusHMDs.Clear();
-
- ovr_Shutdown();
- mOculusInitialized = false;
-}
-
-void
-VRHMDManagerOculusImpl::GetOculusHMDs(nsTArray<nsRefPtr<VRHMDInfo>>& aHMDResult)
-{
- Init();
- for (size_t i = 0; i < mOculusHMDs.Length(); ++i) {
- aHMDResult.AppendElement(mOculusHMDs[i]);
- }
-}
deleted file mode 100644
--- a/gfx/thebes/gfxVR.h
+++ /dev/null
@@ -1,217 +0,0 @@
-/* -*- 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"
-#include "nsIScreen.h"
-#include "nsCOMPtr.h"
-#include "nsRefPtr.h"
-
-#include "mozilla/gfx/2D.h"
-#include "mozilla/EnumeratedArray.h"
-
-namespace mozilla {
-namespace gfx {
-
-enum class VRHMDType : uint16_t {
- Oculus,
- NumHMDTypes
-};
-
-struct VRFieldOfView {
- static VRFieldOfView FromCSSPerspectiveInfo(double aPerspectiveDistance,
- const Point& aPerspectiveOrigin,
- const Point& aTransformOrigin,
- const Rect& aContentRectangle)
- {
- /**/
- return VRFieldOfView();
- }
-
- VRFieldOfView() {}
- VRFieldOfView(double up, double right, double down, double left)
- : upDegrees(up), rightDegrees(right), downDegrees(down), leftDegrees(left)
- {}
-
- 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;
- }
-
- double upDegrees;
- double rightDegrees;
- double downDegrees;
- double leftDegrees;
-};
-
-// 12 floats per vertex. Position, tex coordinates
-// for each channel, and 4 generic attributes
-struct VRDistortionConstants {
- float eyeToSourceScaleAndOffset[4];
- float destinationScaleAndOffset[4];
-};
-
-struct VRDistortionVertex {
- float pos[2];
- float texR[2];
- float texG[2];
- float texB[2];
- float genericAttribs[4];
-};
-
-struct VRDistortionMesh {
- nsTArray<VRDistortionVertex> mVertices;
- nsTArray<uint16_t> mIndices;
-};
-
-struct VRHMDSensorState {
- double timestamp;
- uint32_t flags;
- 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));
- }
-};
-
-/* A pure data struct that can be used to see if
- * the configuration of one HMDInfo matches another; for rendering purposes,
- * really asking "can the rendering details of this one be used for the other"
- */
-struct VRHMDConfiguration {
- VRHMDConfiguration() : hmdType(VRHMDType::NumHMDTypes) {}
-
- bool operator==(const VRHMDConfiguration& other) const {
- return hmdType == other.hmdType &&
- value == other.value &&
- fov[0] == other.fov[0] &&
- fov[1] == other.fov[1];
- }
-
- bool operator!=(const VRHMDConfiguration& other) const {
- return hmdType != other.hmdType ||
- value != other.value ||
- fov[0] != other.fov[0] ||
- fov[1] != other.fov[1];
- }
-
- bool IsValid() const {
- return hmdType != VRHMDType::NumHMDTypes;
- }
-
- VRHMDType hmdType;
- uint32_t value;
- VRFieldOfView fov[2];
-};
-
-class VRHMDInfo {
-public:
- enum Eye {
- Eye_Left,
- Eye_Right,
- NumEyes
- };
-
- enum StateValidFlags {
- State_Position = 1 << 1,
- State_Orientation = 1 << 2
- };
-
-public:
- NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRHMDInfo)
-
- VRHMDType GetType() const { return mType; }
-
- virtual const VRFieldOfView& GetRecommendedEyeFOV(uint32_t whichEye) { return mRecommendedEyeFOV[whichEye]; }
- virtual const VRFieldOfView& GetMaximumEyeFOV(uint32_t whichEye) { return mMaximumEyeFOV[whichEye]; }
-
- const VRHMDConfiguration& GetConfiguration() const { return mConfiguration; }
-
- /* set the FOV for this HMD unit; this triggers a computation of all the remaining bits. Returns false if it fails */
- virtual bool SetFOV(const VRFieldOfView& aFOVLeft, const VRFieldOfView& aFOVRight,
- double zNear, double zFar) = 0;
- const VRFieldOfView& GetEyeFOV(uint32_t whichEye) { return mEyeFOV[whichEye]; }
-
- /* Suggested resolution for rendering a single eye.
- * Assumption is that left/right rendering will be 2x of this size.
- * XXX fix this for vertical displays
- */
- const IntSize& SuggestedEyeResolution() const { return mEyeResolution; }
- const Point3D& GetEyeTranslation(uint32_t whichEye) const { return mEyeTranslation[whichEye]; }
- const Matrix4x4& GetEyeProjectionMatrix(uint32_t whichEye) const { return mEyeProjectionMatrix[whichEye]; }
-
- virtual uint32_t GetSupportedSensorStateBits() { return mSupportedSensorBits; }
- virtual bool StartSensorTracking() = 0;
- virtual VRHMDSensorState GetSensorState(double timeOffset = 0.0) = 0;
- virtual void StopSensorTracking() = 0;
-
- virtual void ZeroSensor() = 0;
-
- virtual void FillDistortionConstants(uint32_t whichEye,
- const IntSize& textureSize, // the full size of the texture
- const IntRect& eyeViewport, // the viewport within the texture for the current eye
- const Size& destViewport, // the size of the destination viewport
- const Rect& destRect, // the rectangle within the dest viewport that this should be rendered
- VRDistortionConstants& values) = 0;
-
- virtual const VRDistortionMesh& GetDistortionMesh(uint32_t whichEye) const { return mDistortionMesh[whichEye]; }
-
- // The nsIScreen that represents this device
- virtual nsIScreen* GetScreen() { return mScreen; }
-
-protected:
- explicit VRHMDInfo(VRHMDType aType) : mType(aType) { MOZ_COUNT_CTOR(VRHMDInfo); }
- virtual ~VRHMDInfo() { MOZ_COUNT_DTOR(VRHMDInfo); }
-
- VRHMDType mType;
- VRHMDConfiguration mConfiguration;
-
- VRFieldOfView mEyeFOV[NumEyes];
- IntSize mEyeResolution;
- Point3D mEyeTranslation[NumEyes];
- Matrix4x4 mEyeProjectionMatrix[NumEyes];
- VRDistortionMesh mDistortionMesh[NumEyes];
- uint32_t mSupportedSensorBits;
-
- VRFieldOfView mRecommendedEyeFOV[NumEyes];
- VRFieldOfView mMaximumEyeFOV[NumEyes];
-
- nsCOMPtr<nsIScreen> mScreen;
-};
-
-class VRHMDManagerOculusImpl;
-class VRHMDManagerOculus {
- static VRHMDManagerOculusImpl *mImpl;
-public:
- static bool PlatformInit();
- static bool Init();
- static void Destroy();
- static void GetOculusHMDs(nsTArray<nsRefPtr<VRHMDInfo> >& aHMDResult);
-};
-
-} // namespace gfx
-} // namespace mozilla
-
-#endif /* GFX_VR_H */
--- a/gfx/thebes/moz.build
+++ b/gfx/thebes/moz.build
@@ -44,17 +44,16 @@ EXPORTS += [
'gfxSharedQuartzSurface.h',
'gfxSkipChars.h',
'gfxSVGGlyphs.h',
'gfxTeeSurface.h',
'gfxTextRun.h',
'gfxTypes.h',
'gfxUserFontSet.h',
'gfxUtils.h',
- 'gfxVR.h',
'GraphicsFilter.h',
'RoundedRect.h',
'SoftwareVsyncSource.h',
'VsyncSource.h',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
EXPORTS += [
@@ -239,17 +238,16 @@ UNIFIED_SOURCES += [
'gfxReusableSharedImageSurfaceWrapper.cpp',
'gfxScriptItemizer.cpp',
'gfxSkipChars.cpp',
'gfxSVGGlyphs.cpp',
'gfxTeeSurface.cpp',
'gfxTextRun.cpp',
'gfxUserFontSet.cpp',
'gfxUtils.cpp',
- 'gfxVR.cpp',
'nsUnicodeRange.cpp',
'SoftwareVsyncSource.cpp',
'VsyncSource.cpp',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
UNIFIED_SOURCES += [
'gfxMacPlatformFontList.mm',
deleted file mode 100644
--- a/gfx/thebes/ovr_capi_dynamic.h
+++ /dev/null
@@ -1,228 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* 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/. */
-
-/* This file contains just the needed struct definitions for
- * interacting with the Oculus VR C API, without needing to #include
- * OVR_CAPI.h directly. Note that it uses the same type names as the
- * CAPI, and cannot be #included at the same time as OVR_CAPI.h. It
- * does not include the entire C API, just want's needed.
- */
-
-#ifdef OVR_CAPI_h
-#warning OVR_CAPI.h included before ovr_capi_dynamic.h, skpping this
-#define mozilla_ovr_capi_dynamic_h_
-#endif
-
-#ifndef mozilla_ovr_capi_dynamic_h_
-#define mozilla_ovr_capi_dynamic_h_
-
-#define OVR_CAPI_LIMITED_MOZILLA 1
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef char ovrBool;
-typedef struct { int x, y; } ovrVector2i;
-typedef struct { int w, h; } ovrSizei;
-typedef struct { ovrVector2i Pos; ovrSizei Size; } ovrRecti;
-typedef struct { float x, y, z, w; } ovrQuatf;
-typedef struct { float x, y; } ovrVector2f;
-typedef struct { float x, y, z; } ovrVector3f;
-typedef struct { float M[4][4]; } ovrMatrix4f;
-
-typedef struct {
- ovrQuatf Orientation;
- ovrVector3f Position;
-} ovrPosef;
-
-typedef struct {
- ovrPosef ThePose;
- ovrVector3f AngularVelocity;
- ovrVector3f LinearVelocity;
- ovrVector3f AngularAcceleration;
- ovrVector3f LinearAcceleration;
- double TimeInSeconds;
-} ovrPoseStatef;
-
-typedef struct {
- float UpTan;
- float DownTan;
- float LeftTan;
- float RightTan;
-} ovrFovPort;
-
-typedef enum {
- ovrHmd_None = 0,
- ovrHmd_DK1 = 3,
- ovrHmd_DKHD = 4,
- ovrHmd_DK2 = 6,
- ovrHmd_Other
-} ovrHmdType;
-
-typedef enum {
- ovrHmdCap_Present = 0x0001,
- ovrHmdCap_Available = 0x0002,
- ovrHmdCap_Captured = 0x0004,
- ovrHmdCap_ExtendDesktop = 0x0008,
- ovrHmdCap_DisplayOff = 0x0040,
- ovrHmdCap_LowPersistence = 0x0080,
- ovrHmdCap_DynamicPrediction = 0x0200,
- ovrHmdCap_NoVSync = 0x1000,
- ovrHmdCap_NoMirrorToWindow = 0x2000
-} ovrHmdCapBits;
-
-typedef enum
-{
- ovrTrackingCap_Orientation = 0x0010,
- ovrTrackingCap_MagYawCorrection = 0x0020,
- ovrTrackingCap_Position = 0x0040,
- ovrTrackingCap_Idle = 0x0100
-} ovrTrackingCaps;
-
-typedef enum {
- ovrDistortionCap_Chromatic = 0x01,
- ovrDistortionCap_TimeWarp = 0x02,
- ovrDistortionCap_Vignette = 0x08,
- ovrDistortionCap_NoRestore = 0x10,
- ovrDistortionCap_FlipInput = 0x20,
- ovrDistortionCap_SRGB = 0x40,
- ovrDistortionCap_Overdrive = 0x80,
- ovrDistortionCap_ProfileNoTimewarpSpinWaits = 0x10000
-} ovrDistortionCaps;
-
-typedef enum {
- ovrEye_Left = 0,
- ovrEye_Right = 1,
- ovrEye_Count = 2
-} ovrEyeType;
-
-typedef struct ovrHmdDesc_ {
- void* Handle;
- ovrHmdType Type;
- const char* ProductName;
- const char* Manufacturer;
- short VendorId;
- short ProductId;
- char SerialNumber[24];
- short FirmwareMajor;
- short FirmwareMinor;
- float CameraFrustumHFovInRadians;
- float CameraFrustumVFovInRadians;
- float CameraFrustumNearZInMeters;
- float CameraFrustumFarZInMeters;
-
- unsigned int HmdCaps;
- unsigned int TrackingCaps;
- unsigned int DistortionCaps;
-
- ovrFovPort DefaultEyeFov[ovrEye_Count];
- ovrFovPort MaxEyeFov[ovrEye_Count];
- ovrEyeType EyeRenderOrder[ovrEye_Count];
-
- ovrSizei Resolution;
- ovrVector2i WindowsPos;
-
- const char* DisplayDeviceName;
- int DisplayId;
-} ovrHmdDesc;
-
-typedef const ovrHmdDesc* ovrHmd;
-
-typedef enum {
- ovrStatus_OrientationTracked = 0x0001,
- ovrStatus_PositionTracked = 0x0002,
- ovrStatus_CameraPoseTracked = 0x0004,
- ovrStatus_PositionConnected = 0x0020,
- ovrStatus_HmdConnected = 0x0080
-} ovrStatusBits;
-
-typedef struct ovrSensorData_ {
- ovrVector3f Accelerometer;
- ovrVector3f Gyro;
- ovrVector3f Magnetometer;
- float Temperature;
- float TimeInSeconds;
-} ovrSensorData;
-
-
-typedef struct ovrTrackingState_ {
- ovrPoseStatef HeadPose;
- ovrPosef CameraPose;
- ovrPosef LeveledCameraPose;
- ovrSensorData RawSensorData;
- unsigned int StatusFlags;
- double LastVisionProcessingTime;
- double LastVisionFrameLatency;
- uint32_t LastCameraFrameCounter;
-} ovrTrackingState;
-
-typedef struct ovrFrameTiming_ {
- float DeltaSeconds;
- double ThisFrameSeconds;
- double TimewarpPointSeconds;
- double NextFrameSeconds;
- double ScanoutMidpointSeconds;
- double EyeScanoutSeconds[2];
-} ovrFrameTiming;
-
-typedef struct ovrEyeRenderDesc_ {
- ovrEyeType Eye;
- ovrFovPort Fov;
- ovrRecti DistortedViewport;
- ovrVector2f PixelsPerTanAngleAtCenter;
- ovrVector3f ViewAdjust;
-} ovrEyeRenderDesc;
-
-typedef struct ovrDistortionVertex_ {
- ovrVector2f ScreenPosNDC;
- float TimeWarpFactor;
- float VignetteFactor;
- ovrVector2f TanEyeAnglesR;
- ovrVector2f TanEyeAnglesG;
- ovrVector2f TanEyeAnglesB;
-} ovrDistortionVertex;
-
-typedef struct ovrDistortionMesh_ {
- ovrDistortionVertex* pVertexData;
- unsigned short* pIndexData;
- unsigned int VertexCount;
- unsigned int IndexCount;
-} ovrDistortionMesh;
-
-typedef ovrBool (*pfn_ovr_Initialize)();
-typedef void (*pfn_ovr_Shutdown)();
-typedef int (*pfn_ovrHmd_Detect)();
-typedef ovrHmd (*pfn_ovrHmd_Create)(int index);
-typedef void (*pfn_ovrHmd_Destroy)(ovrHmd hmd);
-typedef ovrHmd (*pfn_ovrHmd_CreateDebug)(ovrHmdType type);
-typedef const char* (*pfn_ovrHmd_GetLastError)(ovrHmd hmd);
-typedef ovrBool (*pfn_ovrHmd_AttachToWindow)(ovrHmd hmd, void* window, const ovrRecti* destMirrorRect, const ovrRecti* sourceRenderTargetRect);
-typedef unsigned int (*pfn_ovrHmd_GetEnabledCaps)(ovrHmd hmd);
-typedef void (*pfn_ovrHmd_SetEnabledCaps)(ovrHmd hmd, unsigned int hmdCaps);
-typedef ovrBool (*pfn_ovrHmd_ConfigureTracking)(ovrHmd hmd, unsigned int supportedTrackingCaps, unsigned int requiredTrackingCaps);
-typedef void (*pfn_ovrHmd_RecenterPose)(ovrHmd hmd);
-typedef ovrTrackingState (*pfn_ovrHmd_GetTrackingState)(ovrHmd hmd, double absTime);
-typedef ovrSizei (*pfn_ovrHmd_GetFovTextureSize)(ovrHmd hmd, ovrEyeType eye, ovrFovPort fov, float pixelsPerDisplayPixel);
-typedef ovrEyeRenderDesc (*pfn_ovrHmd_GetRenderDesc)(ovrHmd hmd, ovrEyeType eyeType, ovrFovPort fov);
-typedef ovrBool (*pfn_ovrHmd_CreateDistortionMesh)(ovrHmd hmd, ovrEyeType eyeType, ovrFovPort fov, unsigned int distortionCaps, ovrDistortionMesh *meshData);
-typedef void (*pfn_ovrHmd_DestroyDistortionMesh)(ovrDistortionMesh* meshData);
-typedef void (*pfn_ovrHmd_GetRenderScaleAndOffset)(ovrFovPort fov, ovrSizei textureSize, ovrRecti renderViewport, ovrVector2f uvScaleOffsetOut[2]);
-typedef ovrFrameTiming (*pfn_ovrHmd_GetFrameTiming)(ovrHmd hmd, unsigned int frameIndex);
-typedef ovrFrameTiming (*pfn_ovrHmd_BeginFrameTiming)(ovrHmd hmd, unsigned int frameIndex);
-typedef void (*pfn_ovrHmd_EndFrameTiming)(ovrHmd hmd);
-typedef void (*pfn_ovrHmd_ResetFrameTiming)(ovrHmd hmd, unsigned int frameIndex, bool vsync);
-typedef void (*pfn_ovrHmd_GetEyePoses)(ovrHmd hmd, unsigned int frameIndex, ovrVector3f hmdToEyeViewOffset[2], ovrPosef outEyePoses[2], ovrTrackingState* outHmdTrackingState);
-typedef ovrPosef (*pfn_ovrHmd_GetHmdPosePerEye)(ovrHmd hmd, ovrEyeType eye);
-typedef void (*pfn_ovrHmd_GetEyeTimewarpMatrices)(ovrHmd hmd, ovrEyeType eye, ovrPosef renderPose, ovrMatrix4f twmOut[2]);
-typedef ovrMatrix4f (*pfn_ovrMatrix4f_Projection) (ovrFovPort fov, float znear, float zfar, ovrBool rightHanded );
-typedef ovrMatrix4f (*pfn_ovrMatrix4f_OrthoSubProjection) (ovrFovPort fov, ovrVector2f orthoScale, float orthoDistance, float eyeViewAdjustX);
-typedef double (*pfn_ovr_GetTimeInSeconds)();
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* mozilla_ovr_capi_dynamic_h_ */
new file mode 100644
--- /dev/null
+++ b/gfx/vr/gfxVR.cpp
@@ -0,0 +1,658 @@
+/* -*- 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/. */
+
+#include <math.h>
+
+#include "prlink.h"
+#include "prmem.h"
+#include "prenv.h"
+#include "gfxPrefs.h"
+#include "gfxVR.h"
+#include "nsString.h"
+#include "mozilla/Preferences.h"
+
+#include "ovr_capi_dynamic.h"
+
+#include "nsServiceManagerUtils.h"
+#include "nsIScreenManager.h"
+
+#ifdef XP_WIN
+#include "gfxWindowsPlatform.h" // for gfxWindowsPlatform::GetDPIScale
+#endif
+
+#ifndef M_PI
+# define M_PI 3.14159265358979323846
+#endif
+
+namespace {
+
+#ifdef OVR_CAPI_LIMITED_MOZILLA
+static pfn_ovr_Initialize ovr_Initialize = nullptr;
+static pfn_ovr_Shutdown ovr_Shutdown = nullptr;
+static pfn_ovrHmd_Detect ovrHmd_Detect = nullptr;
+static pfn_ovrHmd_Create ovrHmd_Create = nullptr;
+static pfn_ovrHmd_Destroy ovrHmd_Destroy = nullptr;
+static pfn_ovrHmd_CreateDebug ovrHmd_CreateDebug = nullptr;
+static pfn_ovrHmd_GetLastError ovrHmd_GetLastError = nullptr;
+static pfn_ovrHmd_AttachToWindow ovrHmd_AttachToWindow = nullptr;
+static pfn_ovrHmd_GetEnabledCaps ovrHmd_GetEnabledCaps = nullptr;
+static pfn_ovrHmd_SetEnabledCaps ovrHmd_SetEnabledCaps = nullptr;
+static pfn_ovrHmd_ConfigureTracking ovrHmd_ConfigureTracking = nullptr;
+static pfn_ovrHmd_RecenterPose ovrHmd_RecenterPose = nullptr;
+static pfn_ovrHmd_GetTrackingState ovrHmd_GetTrackingState = nullptr;
+static pfn_ovrHmd_GetFovTextureSize ovrHmd_GetFovTextureSize = nullptr;
+static pfn_ovrHmd_GetRenderDesc ovrHmd_GetRenderDesc = nullptr;
+static pfn_ovrHmd_CreateDistortionMesh ovrHmd_CreateDistortionMesh = nullptr;
+static pfn_ovrHmd_DestroyDistortionMesh ovrHmd_DestroyDistortionMesh = nullptr;
+static pfn_ovrHmd_GetRenderScaleAndOffset ovrHmd_GetRenderScaleAndOffset = nullptr;
+static pfn_ovrHmd_GetFrameTiming ovrHmd_GetFrameTiming = nullptr;
+static pfn_ovrHmd_BeginFrameTiming ovrHmd_BeginFrameTiming = nullptr;
+static pfn_ovrHmd_EndFrameTiming ovrHmd_EndFrameTiming = nullptr;
+static pfn_ovrHmd_ResetFrameTiming ovrHmd_ResetFrameTiming = nullptr;
+static pfn_ovrHmd_GetEyePoses ovrHmd_GetEyePoses = nullptr;
+static pfn_ovrHmd_GetHmdPosePerEye ovrHmd_GetHmdPosePerEye = nullptr;
+static pfn_ovrHmd_GetEyeTimewarpMatrices ovrHmd_GetEyeTimewarpMatrices = nullptr;
+static pfn_ovrMatrix4f_Projection ovrMatrix4f_Projection = nullptr;
+static pfn_ovrMatrix4f_OrthoSubProjection ovrMatrix4f_OrthoSubProjection = nullptr;
+static pfn_ovr_GetTimeInSeconds ovr_GetTimeInSeconds = nullptr;
+
+#if defined(XP_WIN)
+# ifdef HAVE_64BIT_BUILD
+# define OVR_LIB_NAME "libovr64.dll"
+# else
+# define OVR_LIB_NAME "libovr.dll"
+# endif
+#elif defined(XP_MACOSX)
+# define OVR_LIB_NAME "libovr.dylib"
+#else
+# define OVR_LIB_NAME 0
+#endif
+
+static bool
+InitializeOculusCAPI()
+{
+ static PRLibrary *ovrlib = nullptr;
+
+ if (!ovrlib) {
+ const char *libName = OVR_LIB_NAME;
+
+ // If the pref is present, we override libName
+ nsAdoptingCString prefLibName = mozilla::Preferences::GetCString("dom.vr.ovr_lib_path");
+ if (prefLibName && prefLibName.get()) {
+ libName = prefLibName.get();
+ }
+
+ // If the env var is present, we override libName
+ if (PR_GetEnv("OVR_LIB_NAME")) {
+ libName = PR_GetEnv("OVR_LIB_NAME");
+ }
+
+ if (!libName) {
+ printf_stderr("Don't know how to find Oculus VR library; missing dom.vr.ovr_lib_path or OVR_LIB_NAME\n");
+ return false;
+ }
+
+ ovrlib = PR_LoadLibrary(libName);
+
+ if (!ovrlib) {
+ // Not found? Try harder. Needed mainly on OSX/etc. where
+ // the binary location is not in the search path.
+ const char *xulName = "libxul.so";
+#if defined(XP_MACOSX)
+ xulName = "XUL";
+#endif
+
+ char *xulpath = PR_GetLibraryFilePathname(xulName, (PRFuncPtr) &InitializeOculusCAPI);
+ if (xulpath) {
+ char *xuldir = strrchr(xulpath, '/');
+ if (xuldir) {
+ *xuldir = 0;
+ xuldir = xulpath;
+
+ char *ovrpath = PR_GetLibraryName(xuldir, libName);
+ ovrlib = PR_LoadLibrary(ovrpath);
+ PR_Free(ovrpath);
+ }
+ PR_Free(xulpath);
+ }
+ }
+
+ if (!ovrlib) {
+ printf_stderr("Failed to load Oculus VR library, tried '%s'\n", libName);
+ return false;
+ }
+ }
+
+ // was it already initialized?
+ if (ovr_Initialize)
+ return true;
+
+#define REQUIRE_FUNCTION(_x) do { \
+ *(void **)&_x = (void *) PR_FindSymbol(ovrlib, #_x); \
+ if (!_x) { printf_stderr(#_x " symbol missing\n"); goto fail; } \
+ } while (0)
+
+ REQUIRE_FUNCTION(ovr_Initialize);
+ REQUIRE_FUNCTION(ovr_Shutdown);
+ REQUIRE_FUNCTION(ovrHmd_Detect);
+ REQUIRE_FUNCTION(ovrHmd_Create);
+ REQUIRE_FUNCTION(ovrHmd_Destroy);
+ REQUIRE_FUNCTION(ovrHmd_CreateDebug);
+ REQUIRE_FUNCTION(ovrHmd_GetLastError);
+ REQUIRE_FUNCTION(ovrHmd_AttachToWindow);
+ REQUIRE_FUNCTION(ovrHmd_GetEnabledCaps);
+ REQUIRE_FUNCTION(ovrHmd_SetEnabledCaps);
+ REQUIRE_FUNCTION(ovrHmd_ConfigureTracking);
+ REQUIRE_FUNCTION(ovrHmd_RecenterPose);
+ REQUIRE_FUNCTION(ovrHmd_GetTrackingState);
+
+ REQUIRE_FUNCTION(ovrHmd_GetFovTextureSize);
+ REQUIRE_FUNCTION(ovrHmd_GetRenderDesc);
+ REQUIRE_FUNCTION(ovrHmd_CreateDistortionMesh);
+ REQUIRE_FUNCTION(ovrHmd_DestroyDistortionMesh);
+ REQUIRE_FUNCTION(ovrHmd_GetRenderScaleAndOffset);
+ REQUIRE_FUNCTION(ovrHmd_GetFrameTiming);
+ REQUIRE_FUNCTION(ovrHmd_BeginFrameTiming);
+ REQUIRE_FUNCTION(ovrHmd_EndFrameTiming);
+ REQUIRE_FUNCTION(ovrHmd_ResetFrameTiming);
+ REQUIRE_FUNCTION(ovrHmd_GetEyePoses);
+ REQUIRE_FUNCTION(ovrHmd_GetHmdPosePerEye);
+ REQUIRE_FUNCTION(ovrHmd_GetEyeTimewarpMatrices);
+ REQUIRE_FUNCTION(ovrMatrix4f_Projection);
+ REQUIRE_FUNCTION(ovrMatrix4f_OrthoSubProjection);
+ REQUIRE_FUNCTION(ovr_GetTimeInSeconds);
+
+#undef REQUIRE_FUNCTION
+
+ return true;
+
+ fail:
+ ovr_Initialize = nullptr;
+ return false;
+}
+
+#else
+// we're statically linked; it's available
+static bool InitializeOculusCAPI()
+{
+ return true;
+}
+#endif
+
+} // anonymous namespace
+
+using namespace mozilla::gfx;
+
+// Dummy nsIScreen implementation, for when we just need to specify a size
+class FakeScreen : public nsIScreen
+{
+public:
+ explicit FakeScreen(const IntRect& aScreenRect)
+ : mScreenRect(aScreenRect)
+ { }
+
+ NS_DECL_ISUPPORTS
+
+ NS_IMETHOD GetRect(int32_t *l, int32_t *t, int32_t *w, int32_t *h) override {
+ *l = mScreenRect.x;
+ *t = mScreenRect.y;
+ *w = mScreenRect.width;
+ *h = mScreenRect.height;
+ return NS_OK;
+ }
+ NS_IMETHOD GetAvailRect(int32_t *l, int32_t *t, int32_t *w, int32_t *h) override {
+ return GetRect(l, t, w, h);
+ }
+ NS_IMETHOD GetRectDisplayPix(int32_t *l, int32_t *t, int32_t *w, int32_t *h) override {
+ return GetRect(l, t, w, h);
+ }
+ NS_IMETHOD GetAvailRectDisplayPix(int32_t *l, int32_t *t, int32_t *w, int32_t *h) override {
+ return GetAvailRect(l, t, w, h);
+ }
+
+ NS_IMETHOD GetId(uint32_t* aId) override { *aId = (uint32_t)-1; return NS_OK; }
+ NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth) override { *aPixelDepth = 24; return NS_OK; }
+ NS_IMETHOD GetColorDepth(int32_t* aColorDepth) override { *aColorDepth = 24; return NS_OK; }
+
+ NS_IMETHOD LockMinimumBrightness(uint32_t aBrightness) override { return NS_ERROR_NOT_AVAILABLE; }
+ NS_IMETHOD UnlockMinimumBrightness(uint32_t aBrightness) override { return NS_ERROR_NOT_AVAILABLE; }
+ NS_IMETHOD GetRotation(uint32_t* aRotation) override {
+ *aRotation = nsIScreen::ROTATION_0_DEG;
+ return NS_OK;
+ }
+ NS_IMETHOD SetRotation(uint32_t aRotation) override { return NS_ERROR_NOT_AVAILABLE; }
+ NS_IMETHOD GetContentsScaleFactor(double* aContentsScaleFactor) override {
+ *aContentsScaleFactor = 1.0;
+ return NS_OK;
+ }
+
+protected:
+ virtual ~FakeScreen() {}
+
+ IntRect mScreenRect;
+};
+
+NS_IMPL_ISUPPORTS(FakeScreen, nsIScreen)
+
+class HMDInfoOculus : public VRHMDInfo {
+ friend class VRHMDManagerOculusImpl;
+public:
+ explicit HMDInfoOculus(ovrHmd aHMD);
+
+ bool SetFOV(const VRFieldOfView& aFOVLeft, const VRFieldOfView& aFOVRight,
+ double zNear, double zFar) override;
+
+ bool StartSensorTracking() override;
+ VRHMDSensorState GetSensorState(double timeOffset) override;
+ void StopSensorTracking() override;
+ void ZeroSensor() override;
+
+ void FillDistortionConstants(uint32_t whichEye,
+ const IntSize& textureSize, const IntRect& eyeViewport,
+ const Size& destViewport, const Rect& destRect,
+ VRDistortionConstants& values) override;
+
+ void Destroy();
+
+protected:
+ virtual ~HMDInfoOculus() {
+ Destroy();
+ MOZ_COUNT_DTOR_INHERITED(HMDInfoOculus, VRHMDInfo);
+ }
+
+ ovrHmd mHMD;
+ ovrFovPort mFOVPort[2];
+ uint32_t mStartCount;
+};
+
+static ovrFovPort
+ToFovPort(const VRFieldOfView& aFOV)
+{
+ ovrFovPort fovPort;
+ fovPort.LeftTan = tan(aFOV.leftDegrees * M_PI / 180.0);
+ fovPort.RightTan = tan(aFOV.rightDegrees * M_PI / 180.0);
+ fovPort.UpTan = tan(aFOV.upDegrees * M_PI / 180.0);
+ fovPort.DownTan = tan(aFOV.downDegrees * M_PI / 180.0);
+ return fovPort;
+}
+
+static VRFieldOfView
+FromFovPort(const ovrFovPort& aFOV)
+{
+ VRFieldOfView fovInfo;
+ fovInfo.leftDegrees = atan(aFOV.LeftTan) * 180.0 / M_PI;
+ fovInfo.rightDegrees = atan(aFOV.RightTan) * 180.0 / M_PI;
+ fovInfo.upDegrees = atan(aFOV.UpTan) * 180.0 / M_PI;
+ fovInfo.downDegrees = atan(aFOV.DownTan) * 180.0 / M_PI;
+ return fovInfo;
+}
+
+HMDInfoOculus::HMDInfoOculus(ovrHmd aHMD)
+ : VRHMDInfo(VRHMDType::Oculus)
+ , mHMD(aHMD)
+ , mStartCount(0)
+{
+ MOZ_COUNT_CTOR_INHERITED(HMDInfoOculus, VRHMDInfo);
+
+ mSupportedSensorBits = 0;
+ if (mHMD->TrackingCaps & ovrTrackingCap_Orientation)
+ mSupportedSensorBits |= State_Orientation;
+ if (mHMD->TrackingCaps & ovrTrackingCap_Position)
+ mSupportedSensorBits |= State_Position;
+
+ mRecommendedEyeFOV[Eye_Left] = FromFovPort(mHMD->DefaultEyeFov[ovrEye_Left]);
+ mRecommendedEyeFOV[Eye_Right] = FromFovPort(mHMD->DefaultEyeFov[ovrEye_Right]);
+
+ mMaximumEyeFOV[Eye_Left] = FromFovPort(mHMD->MaxEyeFov[ovrEye_Left]);
+ mMaximumEyeFOV[Eye_Right] = FromFovPort(mHMD->MaxEyeFov[ovrEye_Right]);
+
+ SetFOV(mRecommendedEyeFOV[Eye_Left], mRecommendedEyeFOV[Eye_Right], 0.01, 10000.0);
+
+ nsCOMPtr<nsIScreenManager> screenmgr = do_GetService("@mozilla.org/gfx/screenmanager;1");
+ if (screenmgr) {
+ screenmgr->ScreenForRect(mHMD->WindowsPos.x, mHMD->WindowsPos.y,
+ mHMD->Resolution.w, mHMD->Resolution.h,
+ getter_AddRefs(mScreen));
+ }
+}
+
+void
+HMDInfoOculus::Destroy()
+{
+ if (mHMD) {
+ ovrHmd_Destroy(mHMD);
+ mHMD = nullptr;
+ }
+}
+
+bool
+HMDInfoOculus::SetFOV(const VRFieldOfView& aFOVLeft, const VRFieldOfView& aFOVRight,
+ double zNear, double zFar)
+{
+ float pixelsPerDisplayPixel = 1.0;
+ ovrSizei texSize[2];
+
+ uint32_t caps = ovrDistortionCap_Chromatic | ovrDistortionCap_Vignette; // XXX TODO add TimeWarp
+
+ // get eye parameters and create the mesh
+ for (uint32_t eye = 0; eye < NumEyes; eye++) {
+ mEyeFOV[eye] = eye == 0 ? aFOVLeft : aFOVRight;
+ mFOVPort[eye] = ToFovPort(mEyeFOV[eye]);
+
+ ovrEyeRenderDesc renderDesc = ovrHmd_GetRenderDesc(mHMD, (ovrEyeType) eye, mFOVPort[eye]);
+
+ // these values are negated so that content can add the adjustment to its camera position,
+ // instead of subtracting
+ mEyeTranslation[eye] = Point3D(-renderDesc.ViewAdjust.x, -renderDesc.ViewAdjust.y, -renderDesc.ViewAdjust.z);
+
+ // note that we are using a right-handed coordinate system here, to match CSS
+ ovrMatrix4f projMatrix = ovrMatrix4f_Projection(mFOVPort[eye], zNear, zFar, true);
+
+ // XXX this is gross, we really need better methods on Matrix4x4
+ memcpy(&mEyeProjectionMatrix[eye], projMatrix.M, sizeof(ovrMatrix4f));
+ mEyeProjectionMatrix[eye].Transpose();
+
+ texSize[eye] = ovrHmd_GetFovTextureSize(mHMD, (ovrEyeType) eye, mFOVPort[eye], pixelsPerDisplayPixel);
+
+ ovrDistortionMesh mesh;
+ bool ok = ovrHmd_CreateDistortionMesh(mHMD, (ovrEyeType) eye, mFOVPort[eye], caps, &mesh);
+ if (!ok)
+ return false;
+
+ mDistortionMesh[eye].mVertices.SetLength(mesh.VertexCount);
+ mDistortionMesh[eye].mIndices.SetLength(mesh.IndexCount);
+
+ ovrDistortionVertex *srcv = mesh.pVertexData;
+ VRDistortionVertex *destv = mDistortionMesh[eye].mVertices.Elements();
+ memset(destv, 0, mesh.VertexCount * sizeof(VRDistortionVertex));
+ for (uint32_t i = 0; i < mesh.VertexCount; ++i) {
+ destv[i].pos[0] = srcv[i].ScreenPosNDC.x;
+ destv[i].pos[1] = srcv[i].ScreenPosNDC.y;
+
+ destv[i].texR[0] = srcv[i].TanEyeAnglesR.x;
+ destv[i].texR[1] = srcv[i].TanEyeAnglesR.y;
+ destv[i].texG[0] = srcv[i].TanEyeAnglesG.x;
+ destv[i].texG[1] = srcv[i].TanEyeAnglesG.y;
+ destv[i].texB[0] = srcv[i].TanEyeAnglesB.x;
+ destv[i].texB[1] = srcv[i].TanEyeAnglesB.y;
+
+ destv[i].genericAttribs[0] = srcv[i].VignetteFactor;
+ destv[i].genericAttribs[1] = srcv[i].TimeWarpFactor;
+ }
+
+ memcpy(mDistortionMesh[eye].mIndices.Elements(), mesh.pIndexData, mesh.IndexCount * sizeof(uint16_t));
+ ovrHmd_DestroyDistortionMesh(&mesh);
+ }
+
+ // take the max of both for eye resolution
+ mEyeResolution.width = std::max(texSize[Eye_Left].w, texSize[Eye_Right].w);
+ mEyeResolution.height = std::max(texSize[Eye_Left].h, texSize[Eye_Right].h);
+
+ mConfiguration.hmdType = mType;
+ mConfiguration.value = 0;
+ mConfiguration.fov[0] = aFOVLeft;
+ mConfiguration.fov[1] = aFOVRight;
+
+ return true;
+ //* need to call this during rendering each frame I think? */
+ //ovrHmd_GetRenderScaleAndOffset(fovPort, texSize, renderViewport, uvScaleOffsetOut);
+}
+
+void
+HMDInfoOculus::FillDistortionConstants(uint32_t whichEye,
+ const IntSize& textureSize,
+ const IntRect& eyeViewport,
+ const Size& destViewport,
+ const Rect& destRect,
+ VRDistortionConstants& values)
+{
+ ovrSizei texSize = { textureSize.width, textureSize.height };
+ ovrRecti eyePort = { { eyeViewport.x, eyeViewport.y }, { eyeViewport.width, eyeViewport.height } };
+ ovrVector2f scaleOut[2];
+
+ ovrHmd_GetRenderScaleAndOffset(mFOVPort[whichEye], texSize, eyePort, scaleOut);
+
+ values.eyeToSourceScaleAndOffset[0] = scaleOut[0].x;
+ values.eyeToSourceScaleAndOffset[1] = scaleOut[0].y;
+ values.eyeToSourceScaleAndOffset[2] = scaleOut[1].x;
+ values.eyeToSourceScaleAndOffset[3] = scaleOut[1].y;
+
+ // These values are in clip space [-1..1] range, but we're providing
+ // scaling in the 0..2 space for sanity.
+
+ // this is the destRect in clip space
+ float x0 = destRect.x / destViewport.width * 2.0 - 1.0;
+ float x1 = (destRect.x + destRect.width) / destViewport.width * 2.0 - 1.0;
+
+ float y0 = destRect.y / destViewport.height * 2.0 - 1.0;
+ float y1 = (destRect.y + destRect.height) / destViewport.height * 2.0 - 1.0;
+
+ // offset
+ values.destinationScaleAndOffset[0] = (x0+x1) / 2.0;
+ values.destinationScaleAndOffset[1] = (y0+y1) / 2.0;
+ // scale
+ values.destinationScaleAndOffset[2] = destRect.width / destViewport.width;
+ values.destinationScaleAndOffset[3] = destRect.height / destViewport.height;
+}
+
+bool
+HMDInfoOculus::StartSensorTracking()
+{
+ if (mStartCount == 0) {
+ bool ok = ovrHmd_ConfigureTracking(mHMD, ovrTrackingCap_Orientation | ovrTrackingCap_Position, 0);
+ if (!ok)
+ return false;
+ }
+
+ mStartCount++;
+ return true;
+}
+
+void
+HMDInfoOculus::StopSensorTracking()
+{
+ if (--mStartCount == 0) {
+ ovrHmd_ConfigureTracking(mHMD, 0, 0);
+ }
+}
+
+void
+HMDInfoOculus::ZeroSensor()
+{
+ ovrHmd_RecenterPose(mHMD);
+}
+
+VRHMDSensorState
+HMDInfoOculus::GetSensorState(double timeOffset)
+{
+ VRHMDSensorState result;
+ result.Clear();
+
+ // XXX this is the wrong time base for timeOffset; we need to figure out how to synchronize
+ // the Oculus time base and the browser one.
+ ovrTrackingState state = ovrHmd_GetTrackingState(mHMD, ovr_GetTimeInSeconds() + timeOffset);
+ ovrPoseStatef& pose(state.HeadPose);
+
+ result.timestamp = pose.TimeInSeconds;
+
+ if (state.StatusFlags & ovrStatus_OrientationTracked) {
+ result.flags |= State_Orientation;
+
+ result.orientation[0] = pose.ThePose.Orientation.x;
+ result.orientation[1] = pose.ThePose.Orientation.y;
+ result.orientation[2] = pose.ThePose.Orientation.z;
+ result.orientation[3] = pose.ThePose.Orientation.w;
+
+ result.angularVelocity[0] = pose.AngularVelocity.x;
+ result.angularVelocity[1] = pose.AngularVelocity.y;
+ result.angularVelocity[2] = pose.AngularVelocity.z;
+
+ result.angularAcceleration[0] = pose.AngularAcceleration.x;
+ result.angularAcceleration[1] = pose.AngularAcceleration.y;
+ result.angularAcceleration[2] = pose.AngularAcceleration.z;
+ }
+
+ if (state.StatusFlags & ovrStatus_PositionTracked) {
+ result.flags |= State_Position;
+
+ result.position[0] = pose.ThePose.Position.x;
+ result.position[1] = pose.ThePose.Position.y;
+ result.position[2] = pose.ThePose.Position.z;
+
+ result.linearVelocity[0] = pose.LinearVelocity.x;
+ result.linearVelocity[1] = pose.LinearVelocity.y;
+ result.linearVelocity[2] = pose.LinearVelocity.z;
+
+ result.linearAcceleration[0] = pose.LinearAcceleration.x;
+ result.linearAcceleration[1] = pose.LinearAcceleration.y;
+ result.linearAcceleration[2] = pose.LinearAcceleration.z;
+ }
+
+ return result;
+}
+
+namespace mozilla {
+namespace gfx {
+
+class VRHMDManagerOculusImpl {
+public:
+ VRHMDManagerOculusImpl() : mOculusInitialized(false), mOculusPlatformInitialized(false)
+ { }
+
+ bool PlatformInit();
+ bool Init();
+ void Destroy();
+ void GetOculusHMDs(nsTArray<nsRefPtr<VRHMDInfo> >& aHMDResult);
+protected:
+ nsTArray<nsRefPtr<HMDInfoOculus>> mOculusHMDs;
+ bool mOculusInitialized;
+ bool mOculusPlatformInitialized;
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+VRHMDManagerOculusImpl *VRHMDManagerOculus::mImpl = nullptr;
+
+// These just forward to the Impl class, to have a non-static container for various
+// objects.
+
+bool
+VRHMDManagerOculus::PlatformInit()
+{
+ if (!mImpl) {
+ mImpl = new VRHMDManagerOculusImpl;
+ }
+ return mImpl->PlatformInit();
+}
+
+bool
+VRHMDManagerOculus::Init()
+{
+ if (!mImpl) {
+ mImpl = new VRHMDManagerOculusImpl;
+ }
+ return mImpl->Init();
+}
+
+void
+VRHMDManagerOculus::GetOculusHMDs(nsTArray<nsRefPtr<VRHMDInfo>>& aHMDResult)
+{
+ if (!mImpl) {
+ mImpl = new VRHMDManagerOculusImpl;
+ }
+ mImpl->GetOculusHMDs(aHMDResult);
+}
+
+void
+VRHMDManagerOculus::Destroy()
+{
+ if (!mImpl)
+ return;
+ mImpl->Destroy();
+ delete mImpl;
+ mImpl = nullptr;
+}
+
+bool
+VRHMDManagerOculusImpl::PlatformInit()
+{
+ if (mOculusPlatformInitialized)
+ return true;
+
+ if (!gfxPrefs::VREnabled())
+ return false;
+
+ if (!InitializeOculusCAPI())
+ return false;
+
+ bool ok = ovr_Initialize();
+
+ if (!ok)
+ return false;
+
+ mOculusPlatformInitialized = true;
+ return true;
+}
+
+bool
+VRHMDManagerOculusImpl::Init()
+{
+ if (mOculusInitialized)
+ return true;
+
+ if (!PlatformInit())
+ return false;
+
+ int count = ovrHmd_Detect();
+
+ for (int i = 0; i < count; ++i) {
+ ovrHmd hmd = ovrHmd_Create(i);
+ if (!hmd)
+ continue;
+ nsRefPtr<HMDInfoOculus> oc = new HMDInfoOculus(hmd);
+ mOculusHMDs.AppendElement(oc);
+ }
+
+ // VRAddTestDevices == 1: add test device only if no real devices present
+ // VRAddTestDevices == 2: add test device always
+ if ((count == 0 && gfxPrefs::VRAddTestDevices() == 1) ||
+ (gfxPrefs::VRAddTestDevices() == 2))
+ {
+ ovrHmd hmd = ovrHmd_CreateDebug(ovrHmd_DK2);
+ if (hmd) {
+ nsRefPtr<HMDInfoOculus> oc = new HMDInfoOculus(hmd);
+ mOculusHMDs.AppendElement(oc);
+ }
+ }
+
+ mOculusInitialized = true;
+ return true;
+}
+
+void
+VRHMDManagerOculusImpl::Destroy()
+{
+ if (!mOculusInitialized)
+ return;
+
+ for (size_t i = 0; i < mOculusHMDs.Length(); ++i) {
+ mOculusHMDs[i]->Destroy();
+ }
+
+ mOculusHMDs.Clear();
+
+ ovr_Shutdown();
+ mOculusInitialized = false;
+}
+
+void
+VRHMDManagerOculusImpl::GetOculusHMDs(nsTArray<nsRefPtr<VRHMDInfo>>& aHMDResult)
+{
+ Init();
+ for (size_t i = 0; i < mOculusHMDs.Length(); ++i) {
+ aHMDResult.AppendElement(mOculusHMDs[i]);
+ }
+}
new file mode 100644
--- /dev/null
+++ b/gfx/vr/gfxVR.h
@@ -0,0 +1,217 @@
+/* -*- 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"
+#include "nsIScreen.h"
+#include "nsCOMPtr.h"
+#include "nsRefPtr.h"
+
+#include "mozilla/gfx/2D.h"
+#include "mozilla/EnumeratedArray.h"
+
+namespace mozilla {
+namespace gfx {
+
+enum class VRHMDType : uint16_t {
+ Oculus,
+ NumHMDTypes
+};
+
+struct VRFieldOfView {
+ static VRFieldOfView FromCSSPerspectiveInfo(double aPerspectiveDistance,
+ const Point& aPerspectiveOrigin,
+ const Point& aTransformOrigin,
+ const Rect& aContentRectangle)
+ {
+ /**/
+ return VRFieldOfView();
+ }
+
+ VRFieldOfView() {}
+ VRFieldOfView(double up, double right, double down, double left)
+ : upDegrees(up), rightDegrees(right), downDegrees(down), leftDegrees(left)
+ {}
+
+ 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;
+ }
+
+ double upDegrees;
+ double rightDegrees;
+ double downDegrees;
+ double leftDegrees;
+};
+
+// 12 floats per vertex. Position, tex coordinates
+// for each channel, and 4 generic attributes
+struct VRDistortionConstants {
+ float eyeToSourceScaleAndOffset[4];
+ float destinationScaleAndOffset[4];
+};
+
+struct VRDistortionVertex {
+ float pos[2];
+ float texR[2];
+ float texG[2];
+ float texB[2];
+ float genericAttribs[4];
+};
+
+struct VRDistortionMesh {
+ nsTArray<VRDistortionVertex> mVertices;
+ nsTArray<uint16_t> mIndices;
+};
+
+struct VRHMDSensorState {
+ double timestamp;
+ uint32_t flags;
+ 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));
+ }
+};
+
+/* A pure data struct that can be used to see if
+ * the configuration of one HMDInfo matches another; for rendering purposes,
+ * really asking "can the rendering details of this one be used for the other"
+ */
+struct VRHMDConfiguration {
+ VRHMDConfiguration() : hmdType(VRHMDType::NumHMDTypes) {}
+
+ bool operator==(const VRHMDConfiguration& other) const {
+ return hmdType == other.hmdType &&
+ value == other.value &&
+ fov[0] == other.fov[0] &&
+ fov[1] == other.fov[1];
+ }
+
+ bool operator!=(const VRHMDConfiguration& other) const {
+ return hmdType != other.hmdType ||
+ value != other.value ||
+ fov[0] != other.fov[0] ||
+ fov[1] != other.fov[1];
+ }
+
+ bool IsValid() const {
+ return hmdType != VRHMDType::NumHMDTypes;
+ }
+
+ VRHMDType hmdType;
+ uint32_t value;
+ VRFieldOfView fov[2];
+};
+
+class VRHMDInfo {
+public:
+ enum Eye {
+ Eye_Left,
+ Eye_Right,
+ NumEyes
+ };
+
+ enum StateValidFlags {
+ State_Position = 1 << 1,
+ State_Orientation = 1 << 2
+ };
+
+public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRHMDInfo)
+
+ VRHMDType GetType() const { return mType; }
+
+ virtual const VRFieldOfView& GetRecommendedEyeFOV(uint32_t whichEye) { return mRecommendedEyeFOV[whichEye]; }
+ virtual const VRFieldOfView& GetMaximumEyeFOV(uint32_t whichEye) { return mMaximumEyeFOV[whichEye]; }
+
+ const VRHMDConfiguration& GetConfiguration() const { return mConfiguration; }
+
+ /* set the FOV for this HMD unit; this triggers a computation of all the remaining bits. Returns false if it fails */
+ virtual bool SetFOV(const VRFieldOfView& aFOVLeft, const VRFieldOfView& aFOVRight,
+ double zNear, double zFar) = 0;
+ const VRFieldOfView& GetEyeFOV(uint32_t whichEye) { return mEyeFOV[whichEye]; }
+
+ /* Suggested resolution for rendering a single eye.
+ * Assumption is that left/right rendering will be 2x of this size.
+ * XXX fix this for vertical displays
+ */
+ const IntSize& SuggestedEyeResolution() const { return mEyeResolution; }
+ const Point3D& GetEyeTranslation(uint32_t whichEye) const { return mEyeTranslation[whichEye]; }
+ const Matrix4x4& GetEyeProjectionMatrix(uint32_t whichEye) const { return mEyeProjectionMatrix[whichEye]; }
+
+ virtual uint32_t GetSupportedSensorStateBits() { return mSupportedSensorBits; }
+ virtual bool StartSensorTracking() = 0;
+ virtual VRHMDSensorState GetSensorState(double timeOffset = 0.0) = 0;
+ virtual void StopSensorTracking() = 0;
+
+ virtual void ZeroSensor() = 0;
+
+ virtual void FillDistortionConstants(uint32_t whichEye,
+ const IntSize& textureSize, // the full size of the texture
+ const IntRect& eyeViewport, // the viewport within the texture for the current eye
+ const Size& destViewport, // the size of the destination viewport
+ const Rect& destRect, // the rectangle within the dest viewport that this should be rendered
+ VRDistortionConstants& values) = 0;
+
+ virtual const VRDistortionMesh& GetDistortionMesh(uint32_t whichEye) const { return mDistortionMesh[whichEye]; }
+
+ // The nsIScreen that represents this device
+ virtual nsIScreen* GetScreen() { return mScreen; }
+
+protected:
+ explicit VRHMDInfo(VRHMDType aType) : mType(aType) { MOZ_COUNT_CTOR(VRHMDInfo); }
+ virtual ~VRHMDInfo() { MOZ_COUNT_DTOR(VRHMDInfo); }
+
+ VRHMDType mType;
+ VRHMDConfiguration mConfiguration;
+
+ VRFieldOfView mEyeFOV[NumEyes];
+ IntSize mEyeResolution;
+ Point3D mEyeTranslation[NumEyes];
+ Matrix4x4 mEyeProjectionMatrix[NumEyes];
+ VRDistortionMesh mDistortionMesh[NumEyes];
+ uint32_t mSupportedSensorBits;
+
+ VRFieldOfView mRecommendedEyeFOV[NumEyes];
+ VRFieldOfView mMaximumEyeFOV[NumEyes];
+
+ nsCOMPtr<nsIScreen> mScreen;
+};
+
+class VRHMDManagerOculusImpl;
+class VRHMDManagerOculus {
+ static VRHMDManagerOculusImpl *mImpl;
+public:
+ static bool PlatformInit();
+ static bool Init();
+ static void Destroy();
+ static void GetOculusHMDs(nsTArray<nsRefPtr<VRHMDInfo> >& aHMDResult);
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif /* GFX_VR_H */
new file mode 100644
--- /dev/null
+++ b/gfx/vr/moz.build
@@ -0,0 +1,31 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+EXPORTS += [
+ 'gfxVR.h',
+]
+
+LOCAL_INCLUDES += [
+ '/gfx/thebes',
+]
+
+UNIFIED_SOURCES += [
+ 'gfxVR.cpp',
+]
+
+CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
+CXXFLAGS += CONFIG['TK_CFLAGS']
+CFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
+CFLAGS += CONFIG['TK_CFLAGS']
+
+FAIL_ON_WARNINGS = not CONFIG['_MSC_VER']
+
+MSVC_ENABLE_PGO = True
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FINAL_LIBRARY = 'xul'
+
new file mode 100644
--- /dev/null
+++ b/gfx/vr/ovr_capi_dynamic.h
@@ -0,0 +1,228 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* 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/. */
+
+/* This file contains just the needed struct definitions for
+ * interacting with the Oculus VR C API, without needing to #include
+ * OVR_CAPI.h directly. Note that it uses the same type names as the
+ * CAPI, and cannot be #included at the same time as OVR_CAPI.h. It
+ * does not include the entire C API, just want's needed.
+ */
+
+#ifdef OVR_CAPI_h
+#warning OVR_CAPI.h included before ovr_capi_dynamic.h, skpping this
+#define mozilla_ovr_capi_dynamic_h_
+#endif
+
+#ifndef mozilla_ovr_capi_dynamic_h_
+#define mozilla_ovr_capi_dynamic_h_
+
+#define OVR_CAPI_LIMITED_MOZILLA 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef char ovrBool;
+typedef struct { int x, y; } ovrVector2i;
+typedef struct { int w, h; } ovrSizei;
+typedef struct { ovrVector2i Pos; ovrSizei Size; } ovrRecti;
+typedef struct { float x, y, z, w; } ovrQuatf;
+typedef struct { float x, y; } ovrVector2f;
+typedef struct { float x, y, z; } ovrVector3f;
+typedef struct { float M[4][4]; } ovrMatrix4f;
+
+typedef struct {
+ ovrQuatf Orientation;
+ ovrVector3f Position;
+} ovrPosef;
+
+typedef struct {
+ ovrPosef ThePose;
+ ovrVector3f AngularVelocity;
+ ovrVector3f LinearVelocity;
+ ovrVector3f AngularAcceleration;
+ ovrVector3f LinearAcceleration;
+ double TimeInSeconds;
+} ovrPoseStatef;
+
+typedef struct {
+ float UpTan;
+ float DownTan;
+ float LeftTan;
+ float RightTan;
+} ovrFovPort;
+
+typedef enum {
+ ovrHmd_None = 0,
+ ovrHmd_DK1 = 3,
+ ovrHmd_DKHD = 4,
+ ovrHmd_DK2 = 6,
+ ovrHmd_Other
+} ovrHmdType;
+
+typedef enum {
+ ovrHmdCap_Present = 0x0001,
+ ovrHmdCap_Available = 0x0002,
+ ovrHmdCap_Captured = 0x0004,
+ ovrHmdCap_ExtendDesktop = 0x0008,
+ ovrHmdCap_DisplayOff = 0x0040,
+ ovrHmdCap_LowPersistence = 0x0080,
+ ovrHmdCap_DynamicPrediction = 0x0200,
+ ovrHmdCap_NoVSync = 0x1000,
+ ovrHmdCap_NoMirrorToWindow = 0x2000
+} ovrHmdCapBits;
+
+typedef enum
+{
+ ovrTrackingCap_Orientation = 0x0010,
+ ovrTrackingCap_MagYawCorrection = 0x0020,
+ ovrTrackingCap_Position = 0x0040,
+ ovrTrackingCap_Idle = 0x0100
+} ovrTrackingCaps;
+
+typedef enum {
+ ovrDistortionCap_Chromatic = 0x01,
+ ovrDistortionCap_TimeWarp = 0x02,
+ ovrDistortionCap_Vignette = 0x08,
+ ovrDistortionCap_NoRestore = 0x10,
+ ovrDistortionCap_FlipInput = 0x20,
+ ovrDistortionCap_SRGB = 0x40,
+ ovrDistortionCap_Overdrive = 0x80,
+ ovrDistortionCap_ProfileNoTimewarpSpinWaits = 0x10000
+} ovrDistortionCaps;
+
+typedef enum {
+ ovrEye_Left = 0,
+ ovrEye_Right = 1,
+ ovrEye_Count = 2
+} ovrEyeType;
+
+typedef struct ovrHmdDesc_ {
+ void* Handle;
+ ovrHmdType Type;
+ const char* ProductName;
+ const char* Manufacturer;
+ short VendorId;
+ short ProductId;
+ char SerialNumber[24];
+ short FirmwareMajor;
+ short FirmwareMinor;
+ float CameraFrustumHFovInRadians;
+ float CameraFrustumVFovInRadians;
+ float CameraFrustumNearZInMeters;
+ float CameraFrustumFarZInMeters;
+
+ unsigned int HmdCaps;
+ unsigned int TrackingCaps;
+ unsigned int DistortionCaps;
+
+ ovrFovPort DefaultEyeFov[ovrEye_Count];
+ ovrFovPort MaxEyeFov[ovrEye_Count];
+ ovrEyeType EyeRenderOrder[ovrEye_Count];
+
+ ovrSizei Resolution;
+ ovrVector2i WindowsPos;
+
+ const char* DisplayDeviceName;
+ int DisplayId;
+} ovrHmdDesc;
+
+typedef const ovrHmdDesc* ovrHmd;
+
+typedef enum {
+ ovrStatus_OrientationTracked = 0x0001,
+ ovrStatus_PositionTracked = 0x0002,
+ ovrStatus_CameraPoseTracked = 0x0004,
+ ovrStatus_PositionConnected = 0x0020,
+ ovrStatus_HmdConnected = 0x0080
+} ovrStatusBits;
+
+typedef struct ovrSensorData_ {
+ ovrVector3f Accelerometer;
+ ovrVector3f Gyro;
+ ovrVector3f Magnetometer;
+ float Temperature;
+ float TimeInSeconds;
+} ovrSensorData;
+
+
+typedef struct ovrTrackingState_ {
+ ovrPoseStatef HeadPose;
+ ovrPosef CameraPose;
+ ovrPosef LeveledCameraPose;
+ ovrSensorData RawSensorData;
+ unsigned int StatusFlags;
+ double LastVisionProcessingTime;
+ double LastVisionFrameLatency;
+ uint32_t LastCameraFrameCounter;
+} ovrTrackingState;
+
+typedef struct ovrFrameTiming_ {
+ float DeltaSeconds;
+ double ThisFrameSeconds;
+ double TimewarpPointSeconds;
+ double NextFrameSeconds;
+ double ScanoutMidpointSeconds;
+ double EyeScanoutSeconds[2];
+} ovrFrameTiming;
+
+typedef struct ovrEyeRenderDesc_ {
+ ovrEyeType Eye;
+ ovrFovPort Fov;
+ ovrRecti DistortedViewport;
+ ovrVector2f PixelsPerTanAngleAtCenter;
+ ovrVector3f ViewAdjust;
+} ovrEyeRenderDesc;
+
+typedef struct ovrDistortionVertex_ {
+ ovrVector2f ScreenPosNDC;
+ float TimeWarpFactor;
+ float VignetteFactor;
+ ovrVector2f TanEyeAnglesR;
+ ovrVector2f TanEyeAnglesG;
+ ovrVector2f TanEyeAnglesB;
+} ovrDistortionVertex;
+
+typedef struct ovrDistortionMesh_ {
+ ovrDistortionVertex* pVertexData;
+ unsigned short* pIndexData;
+ unsigned int VertexCount;
+ unsigned int IndexCount;
+} ovrDistortionMesh;
+
+typedef ovrBool (*pfn_ovr_Initialize)();
+typedef void (*pfn_ovr_Shutdown)();
+typedef int (*pfn_ovrHmd_Detect)();
+typedef ovrHmd (*pfn_ovrHmd_Create)(int index);
+typedef void (*pfn_ovrHmd_Destroy)(ovrHmd hmd);
+typedef ovrHmd (*pfn_ovrHmd_CreateDebug)(ovrHmdType type);
+typedef const char* (*pfn_ovrHmd_GetLastError)(ovrHmd hmd);
+typedef ovrBool (*pfn_ovrHmd_AttachToWindow)(ovrHmd hmd, void* window, const ovrRecti* destMirrorRect, const ovrRecti* sourceRenderTargetRect);
+typedef unsigned int (*pfn_ovrHmd_GetEnabledCaps)(ovrHmd hmd);
+typedef void (*pfn_ovrHmd_SetEnabledCaps)(ovrHmd hmd, unsigned int hmdCaps);
+typedef ovrBool (*pfn_ovrHmd_ConfigureTracking)(ovrHmd hmd, unsigned int supportedTrackingCaps, unsigned int requiredTrackingCaps);
+typedef void (*pfn_ovrHmd_RecenterPose)(ovrHmd hmd);
+typedef ovrTrackingState (*pfn_ovrHmd_GetTrackingState)(ovrHmd hmd, double absTime);
+typedef ovrSizei (*pfn_ovrHmd_GetFovTextureSize)(ovrHmd hmd, ovrEyeType eye, ovrFovPort fov, float pixelsPerDisplayPixel);
+typedef ovrEyeRenderDesc (*pfn_ovrHmd_GetRenderDesc)(ovrHmd hmd, ovrEyeType eyeType, ovrFovPort fov);
+typedef ovrBool (*pfn_ovrHmd_CreateDistortionMesh)(ovrHmd hmd, ovrEyeType eyeType, ovrFovPort fov, unsigned int distortionCaps, ovrDistortionMesh *meshData);
+typedef void (*pfn_ovrHmd_DestroyDistortionMesh)(ovrDistortionMesh* meshData);
+typedef void (*pfn_ovrHmd_GetRenderScaleAndOffset)(ovrFovPort fov, ovrSizei textureSize, ovrRecti renderViewport, ovrVector2f uvScaleOffsetOut[2]);
+typedef ovrFrameTiming (*pfn_ovrHmd_GetFrameTiming)(ovrHmd hmd, unsigned int frameIndex);
+typedef ovrFrameTiming (*pfn_ovrHmd_BeginFrameTiming)(ovrHmd hmd, unsigned int frameIndex);
+typedef void (*pfn_ovrHmd_EndFrameTiming)(ovrHmd hmd);
+typedef void (*pfn_ovrHmd_ResetFrameTiming)(ovrHmd hmd, unsigned int frameIndex, bool vsync);
+typedef void (*pfn_ovrHmd_GetEyePoses)(ovrHmd hmd, unsigned int frameIndex, ovrVector3f hmdToEyeViewOffset[2], ovrPosef outEyePoses[2], ovrTrackingState* outHmdTrackingState);
+typedef ovrPosef (*pfn_ovrHmd_GetHmdPosePerEye)(ovrHmd hmd, ovrEyeType eye);
+typedef void (*pfn_ovrHmd_GetEyeTimewarpMatrices)(ovrHmd hmd, ovrEyeType eye, ovrPosef renderPose, ovrMatrix4f twmOut[2]);
+typedef ovrMatrix4f (*pfn_ovrMatrix4f_Projection) (ovrFovPort fov, float znear, float zfar, ovrBool rightHanded );
+typedef ovrMatrix4f (*pfn_ovrMatrix4f_OrthoSubProjection) (ovrFovPort fov, ovrVector2f orthoScale, float orthoDistance, float eyeViewAdjustX);
+typedef double (*pfn_ovr_GetTimeInSeconds)();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* mozilla_ovr_capi_dynamic_h_ */