Bumping manifests a=b2g-bump
[gecko.git] / gfx / thebes / gfxVR.cpp
blobb4c1f8d1aa55a1211e53ced6737dc7c1b9f6db93
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include <math.h>
8 #include "prlink.h"
9 #include "prmem.h"
10 #include "prenv.h"
11 #include "gfxPrefs.h"
12 #include "gfxVR.h"
13 #include "nsString.h"
14 #include "mozilla/Preferences.h"
16 #include "ovr_capi_dynamic.h"
18 #include "nsServiceManagerUtils.h"
19 #include "nsIScreenManager.h"
21 #ifdef XP_WIN
22 #include "gfxWindowsPlatform.h" // for gfxWindowsPlatform::GetDPIScale
23 #endif
25 #ifndef M_PI
26 # define M_PI 3.14159265358979323846
27 #endif
29 namespace {
31 #ifdef OVR_CAPI_LIMITED_MOZILLA
32 static pfn_ovr_Initialize ovr_Initialize = nullptr;
33 static pfn_ovr_Shutdown ovr_Shutdown = nullptr;
34 static pfn_ovrHmd_Detect ovrHmd_Detect = nullptr;
35 static pfn_ovrHmd_Create ovrHmd_Create = nullptr;
36 static pfn_ovrHmd_Destroy ovrHmd_Destroy = nullptr;
37 static pfn_ovrHmd_CreateDebug ovrHmd_CreateDebug = nullptr;
38 static pfn_ovrHmd_GetLastError ovrHmd_GetLastError = nullptr;
39 static pfn_ovrHmd_AttachToWindow ovrHmd_AttachToWindow = nullptr;
40 static pfn_ovrHmd_GetEnabledCaps ovrHmd_GetEnabledCaps = nullptr;
41 static pfn_ovrHmd_SetEnabledCaps ovrHmd_SetEnabledCaps = nullptr;
42 static pfn_ovrHmd_ConfigureTracking ovrHmd_ConfigureTracking = nullptr;
43 static pfn_ovrHmd_RecenterPose ovrHmd_RecenterPose = nullptr;
44 static pfn_ovrHmd_GetTrackingState ovrHmd_GetTrackingState = nullptr;
45 static pfn_ovrHmd_GetFovTextureSize ovrHmd_GetFovTextureSize = nullptr;
46 static pfn_ovrHmd_GetRenderDesc ovrHmd_GetRenderDesc = nullptr;
47 static pfn_ovrHmd_CreateDistortionMesh ovrHmd_CreateDistortionMesh = nullptr;
48 static pfn_ovrHmd_DestroyDistortionMesh ovrHmd_DestroyDistortionMesh = nullptr;
49 static pfn_ovrHmd_GetRenderScaleAndOffset ovrHmd_GetRenderScaleAndOffset = nullptr;
50 static pfn_ovrHmd_GetFrameTiming ovrHmd_GetFrameTiming = nullptr;
51 static pfn_ovrHmd_BeginFrameTiming ovrHmd_BeginFrameTiming = nullptr;
52 static pfn_ovrHmd_EndFrameTiming ovrHmd_EndFrameTiming = nullptr;
53 static pfn_ovrHmd_ResetFrameTiming ovrHmd_ResetFrameTiming = nullptr;
54 static pfn_ovrHmd_GetEyePoses ovrHmd_GetEyePoses = nullptr;
55 static pfn_ovrHmd_GetHmdPosePerEye ovrHmd_GetHmdPosePerEye = nullptr;
56 static pfn_ovrHmd_GetEyeTimewarpMatrices ovrHmd_GetEyeTimewarpMatrices = nullptr;
57 static pfn_ovrMatrix4f_Projection ovrMatrix4f_Projection = nullptr;
58 static pfn_ovrMatrix4f_OrthoSubProjection ovrMatrix4f_OrthoSubProjection = nullptr;
59 static pfn_ovr_GetTimeInSeconds ovr_GetTimeInSeconds = nullptr;
61 #if defined(XP_WIN)
62 # ifdef HAVE_64BIT_BUILD
63 # define OVR_LIB_NAME "libovr64.dll"
64 # else
65 # define OVR_LIB_NAME "libovr.dll"
66 # endif
67 #elif defined(XP_MACOSX)
68 # define OVR_LIB_NAME "libovr.dylib"
69 #else
70 # define OVR_LIB_NAME 0
71 #endif
73 static bool
74 InitializeOculusCAPI()
76 static PRLibrary *ovrlib = nullptr;
78 if (!ovrlib) {
79 const char *libName = OVR_LIB_NAME;
81 // If the pref is present, we override libName
82 nsAdoptingCString prefLibName = mozilla::Preferences::GetCString("dom.vr.ovr_lib_path");
83 if (prefLibName && prefLibName.get()) {
84 libName = prefLibName.get();
87 // If the env var is present, we override libName
88 if (PR_GetEnv("OVR_LIB_NAME")) {
89 libName = PR_GetEnv("OVR_LIB_NAME");
92 if (!libName) {
93 printf_stderr("Don't know how to find Oculus VR library; missing dom.vr.ovr_lib_path or OVR_LIB_NAME\n");
94 return false;
97 ovrlib = PR_LoadLibrary(libName);
99 if (!ovrlib) {
100 // Not found? Try harder. Needed mainly on OSX/etc. where
101 // the binary location is not in the search path.
102 const char *xulName = "libxul.so";
103 #if defined(XP_MACOSX)
104 xulName = "XUL";
105 #endif
107 char *xulpath = PR_GetLibraryFilePathname(xulName, (PRFuncPtr) &InitializeOculusCAPI);
108 if (xulpath) {
109 char *xuldir = strrchr(xulpath, '/');
110 if (xuldir) {
111 *xuldir = 0;
112 xuldir = xulpath;
114 char *ovrpath = PR_GetLibraryName(xuldir, libName);
115 ovrlib = PR_LoadLibrary(ovrpath);
116 PR_Free(ovrpath);
118 PR_Free(xulpath);
122 if (!ovrlib) {
123 printf_stderr("Failed to load Oculus VR library, tried '%s'\n", libName);
124 return false;
128 // was it already initialized?
129 if (ovr_Initialize)
130 return true;
132 #define REQUIRE_FUNCTION(_x) do { \
133 *(void **)&_x = (void *) PR_FindSymbol(ovrlib, #_x); \
134 if (!_x) { printf_stderr(#_x " symbol missing\n"); goto fail; } \
135 } while (0)
137 REQUIRE_FUNCTION(ovr_Initialize);
138 REQUIRE_FUNCTION(ovr_Shutdown);
139 REQUIRE_FUNCTION(ovrHmd_Detect);
140 REQUIRE_FUNCTION(ovrHmd_Create);
141 REQUIRE_FUNCTION(ovrHmd_Destroy);
142 REQUIRE_FUNCTION(ovrHmd_CreateDebug);
143 REQUIRE_FUNCTION(ovrHmd_GetLastError);
144 REQUIRE_FUNCTION(ovrHmd_AttachToWindow);
145 REQUIRE_FUNCTION(ovrHmd_GetEnabledCaps);
146 REQUIRE_FUNCTION(ovrHmd_SetEnabledCaps);
147 REQUIRE_FUNCTION(ovrHmd_ConfigureTracking);
148 REQUIRE_FUNCTION(ovrHmd_RecenterPose);
149 REQUIRE_FUNCTION(ovrHmd_GetTrackingState);
151 REQUIRE_FUNCTION(ovrHmd_GetFovTextureSize);
152 REQUIRE_FUNCTION(ovrHmd_GetRenderDesc);
153 REQUIRE_FUNCTION(ovrHmd_CreateDistortionMesh);
154 REQUIRE_FUNCTION(ovrHmd_DestroyDistortionMesh);
155 REQUIRE_FUNCTION(ovrHmd_GetRenderScaleAndOffset);
156 REQUIRE_FUNCTION(ovrHmd_GetFrameTiming);
157 REQUIRE_FUNCTION(ovrHmd_BeginFrameTiming);
158 REQUIRE_FUNCTION(ovrHmd_EndFrameTiming);
159 REQUIRE_FUNCTION(ovrHmd_ResetFrameTiming);
160 REQUIRE_FUNCTION(ovrHmd_GetEyePoses);
161 REQUIRE_FUNCTION(ovrHmd_GetHmdPosePerEye);
162 REQUIRE_FUNCTION(ovrHmd_GetEyeTimewarpMatrices);
163 REQUIRE_FUNCTION(ovrMatrix4f_Projection);
164 REQUIRE_FUNCTION(ovrMatrix4f_OrthoSubProjection);
165 REQUIRE_FUNCTION(ovr_GetTimeInSeconds);
167 #undef REQUIRE_FUNCTION
169 return true;
171 fail:
172 ovr_Initialize = nullptr;
173 return false;
176 #else
177 // we're statically linked; it's available
178 static bool InitializeOculusCAPI()
180 return true;
182 #endif
184 } // anonymous namespace
186 using namespace mozilla::gfx;
188 // Dummy nsIScreen implementation, for when we just need to specify a size
189 class FakeScreen : public nsIScreen
191 public:
192 explicit FakeScreen(const IntRect& aScreenRect)
193 : mScreenRect(aScreenRect)
196 NS_DECL_ISUPPORTS
198 NS_IMETHOD GetRect(int32_t *l, int32_t *t, int32_t *w, int32_t *h) MOZ_OVERRIDE {
199 *l = mScreenRect.x;
200 *t = mScreenRect.y;
201 *w = mScreenRect.width;
202 *h = mScreenRect.height;
203 return NS_OK;
205 NS_IMETHOD GetAvailRect(int32_t *l, int32_t *t, int32_t *w, int32_t *h) MOZ_OVERRIDE {
206 return GetRect(l, t, w, h);
208 NS_IMETHOD GetRectDisplayPix(int32_t *l, int32_t *t, int32_t *w, int32_t *h) MOZ_OVERRIDE {
209 return GetRect(l, t, w, h);
211 NS_IMETHOD GetAvailRectDisplayPix(int32_t *l, int32_t *t, int32_t *w, int32_t *h) MOZ_OVERRIDE {
212 return GetAvailRect(l, t, w, h);
215 NS_IMETHOD GetId(uint32_t* aId) MOZ_OVERRIDE { *aId = (uint32_t)-1; return NS_OK; }
216 NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth) MOZ_OVERRIDE { *aPixelDepth = 24; return NS_OK; }
217 NS_IMETHOD GetColorDepth(int32_t* aColorDepth) MOZ_OVERRIDE { *aColorDepth = 24; return NS_OK; }
219 NS_IMETHOD LockMinimumBrightness(uint32_t aBrightness) MOZ_OVERRIDE { return NS_ERROR_NOT_AVAILABLE; }
220 NS_IMETHOD UnlockMinimumBrightness(uint32_t aBrightness) MOZ_OVERRIDE { return NS_ERROR_NOT_AVAILABLE; }
221 NS_IMETHOD GetRotation(uint32_t* aRotation) MOZ_OVERRIDE {
222 *aRotation = nsIScreen::ROTATION_0_DEG;
223 return NS_OK;
225 NS_IMETHOD SetRotation(uint32_t aRotation) MOZ_OVERRIDE { return NS_ERROR_NOT_AVAILABLE; }
226 NS_IMETHOD GetContentsScaleFactor(double* aContentsScaleFactor) MOZ_OVERRIDE {
227 *aContentsScaleFactor = 1.0;
228 return NS_OK;
231 protected:
232 virtual ~FakeScreen() {}
234 IntRect mScreenRect;
237 NS_IMPL_ISUPPORTS(FakeScreen, nsIScreen)
239 class HMDInfoOculus : public VRHMDInfo {
240 friend class VRHMDManagerOculusImpl;
241 public:
242 explicit HMDInfoOculus(ovrHmd aHMD);
244 bool SetFOV(const VRFieldOfView& aFOVLeft, const VRFieldOfView& aFOVRight,
245 double zNear, double zFar) MOZ_OVERRIDE;
247 bool StartSensorTracking() MOZ_OVERRIDE;
248 VRHMDSensorState GetSensorState(double timeOffset) MOZ_OVERRIDE;
249 void StopSensorTracking() MOZ_OVERRIDE;
250 void ZeroSensor() MOZ_OVERRIDE;
252 void FillDistortionConstants(uint32_t whichEye,
253 const IntSize& textureSize, const IntRect& eyeViewport,
254 const Size& destViewport, const Rect& destRect,
255 VRDistortionConstants& values) MOZ_OVERRIDE;
257 void Destroy();
259 protected:
260 virtual ~HMDInfoOculus() {
261 Destroy();
262 MOZ_COUNT_DTOR_INHERITED(HMDInfoOculus, VRHMDInfo);
265 ovrHmd mHMD;
266 ovrFovPort mFOVPort[2];
267 uint32_t mStartCount;
270 static ovrFovPort
271 ToFovPort(const VRFieldOfView& aFOV)
273 ovrFovPort fovPort;
274 fovPort.LeftTan = tan(aFOV.leftDegrees * M_PI / 180.0);
275 fovPort.RightTan = tan(aFOV.rightDegrees * M_PI / 180.0);
276 fovPort.UpTan = tan(aFOV.upDegrees * M_PI / 180.0);
277 fovPort.DownTan = tan(aFOV.downDegrees * M_PI / 180.0);
278 return fovPort;
281 static VRFieldOfView
282 FromFovPort(const ovrFovPort& aFOV)
284 VRFieldOfView fovInfo;
285 fovInfo.leftDegrees = atan(aFOV.LeftTan) * 180.0 / M_PI;
286 fovInfo.rightDegrees = atan(aFOV.RightTan) * 180.0 / M_PI;
287 fovInfo.upDegrees = atan(aFOV.UpTan) * 180.0 / M_PI;
288 fovInfo.downDegrees = atan(aFOV.DownTan) * 180.0 / M_PI;
289 return fovInfo;
292 HMDInfoOculus::HMDInfoOculus(ovrHmd aHMD)
293 : VRHMDInfo(VRHMDType::Oculus)
294 , mHMD(aHMD)
295 , mStartCount(0)
297 MOZ_COUNT_CTOR_INHERITED(HMDInfoOculus, VRHMDInfo);
299 mSupportedSensorBits = 0;
300 if (mHMD->TrackingCaps & ovrTrackingCap_Orientation)
301 mSupportedSensorBits |= State_Orientation;
302 if (mHMD->TrackingCaps & ovrTrackingCap_Position)
303 mSupportedSensorBits |= State_Position;
305 mRecommendedEyeFOV[Eye_Left] = FromFovPort(mHMD->DefaultEyeFov[ovrEye_Left]);
306 mRecommendedEyeFOV[Eye_Right] = FromFovPort(mHMD->DefaultEyeFov[ovrEye_Right]);
308 mMaximumEyeFOV[Eye_Left] = FromFovPort(mHMD->MaxEyeFov[ovrEye_Left]);
309 mMaximumEyeFOV[Eye_Right] = FromFovPort(mHMD->MaxEyeFov[ovrEye_Right]);
311 SetFOV(mRecommendedEyeFOV[Eye_Left], mRecommendedEyeFOV[Eye_Right], 0.01, 10000.0);
313 nsCOMPtr<nsIScreenManager> screenmgr = do_GetService("@mozilla.org/gfx/screenmanager;1");
314 if (screenmgr) {
315 screenmgr->ScreenForRect(mHMD->WindowsPos.x, mHMD->WindowsPos.y,
316 mHMD->Resolution.w, mHMD->Resolution.h,
317 getter_AddRefs(mScreen));
321 void
322 HMDInfoOculus::Destroy()
324 if (mHMD) {
325 ovrHmd_Destroy(mHMD);
326 mHMD = nullptr;
330 bool
331 HMDInfoOculus::SetFOV(const VRFieldOfView& aFOVLeft, const VRFieldOfView& aFOVRight,
332 double zNear, double zFar)
334 float pixelsPerDisplayPixel = 1.0;
335 ovrSizei texSize[2];
337 uint32_t caps = ovrDistortionCap_Chromatic | ovrDistortionCap_Vignette; // XXX TODO add TimeWarp
339 // get eye parameters and create the mesh
340 for (uint32_t eye = 0; eye < NumEyes; eye++) {
341 mEyeFOV[eye] = eye == 0 ? aFOVLeft : aFOVRight;
342 mFOVPort[eye] = ToFovPort(mEyeFOV[eye]);
344 ovrEyeRenderDesc renderDesc = ovrHmd_GetRenderDesc(mHMD, (ovrEyeType) eye, mFOVPort[eye]);
346 // these values are negated so that content can add the adjustment to its camera position,
347 // instead of subtracting
348 mEyeTranslation[eye] = Point3D(-renderDesc.ViewAdjust.x, -renderDesc.ViewAdjust.y, -renderDesc.ViewAdjust.z);
350 // note that we are using a right-handed coordinate system here, to match CSS
351 ovrMatrix4f projMatrix = ovrMatrix4f_Projection(mFOVPort[eye], zNear, zFar, true);
353 // XXX this is gross, we really need better methods on Matrix4x4
354 memcpy(&mEyeProjectionMatrix[eye], projMatrix.M, sizeof(ovrMatrix4f));
355 mEyeProjectionMatrix[eye].Transpose();
357 texSize[eye] = ovrHmd_GetFovTextureSize(mHMD, (ovrEyeType) eye, mFOVPort[eye], pixelsPerDisplayPixel);
359 ovrDistortionMesh mesh;
360 bool ok = ovrHmd_CreateDistortionMesh(mHMD, (ovrEyeType) eye, mFOVPort[eye], caps, &mesh);
361 if (!ok)
362 return false;
364 mDistortionMesh[eye].mVertices.SetLength(mesh.VertexCount);
365 mDistortionMesh[eye].mIndices.SetLength(mesh.IndexCount);
367 ovrDistortionVertex *srcv = mesh.pVertexData;
368 VRDistortionVertex *destv = mDistortionMesh[eye].mVertices.Elements();
369 memset(destv, 0, mesh.VertexCount * sizeof(VRDistortionVertex));
370 for (uint32_t i = 0; i < mesh.VertexCount; ++i) {
371 destv[i].pos[0] = srcv[i].ScreenPosNDC.x;
372 destv[i].pos[1] = srcv[i].ScreenPosNDC.y;
374 destv[i].texR[0] = srcv[i].TanEyeAnglesR.x;
375 destv[i].texR[1] = srcv[i].TanEyeAnglesR.y;
376 destv[i].texG[0] = srcv[i].TanEyeAnglesG.x;
377 destv[i].texG[1] = srcv[i].TanEyeAnglesG.y;
378 destv[i].texB[0] = srcv[i].TanEyeAnglesB.x;
379 destv[i].texB[1] = srcv[i].TanEyeAnglesB.y;
381 destv[i].genericAttribs[0] = srcv[i].VignetteFactor;
382 destv[i].genericAttribs[1] = srcv[i].TimeWarpFactor;
385 memcpy(mDistortionMesh[eye].mIndices.Elements(), mesh.pIndexData, mesh.IndexCount * sizeof(uint16_t));
386 ovrHmd_DestroyDistortionMesh(&mesh);
389 // take the max of both for eye resolution
390 mEyeResolution.width = std::max(texSize[Eye_Left].w, texSize[Eye_Right].w);
391 mEyeResolution.height = std::max(texSize[Eye_Left].h, texSize[Eye_Right].h);
393 mConfiguration.hmdType = mType;
394 mConfiguration.value = 0;
395 mConfiguration.fov[0] = aFOVLeft;
396 mConfiguration.fov[1] = aFOVRight;
398 return true;
399 //* need to call this during rendering each frame I think? */
400 //ovrHmd_GetRenderScaleAndOffset(fovPort, texSize, renderViewport, uvScaleOffsetOut);
403 void
404 HMDInfoOculus::FillDistortionConstants(uint32_t whichEye,
405 const IntSize& textureSize,
406 const IntRect& eyeViewport,
407 const Size& destViewport,
408 const Rect& destRect,
409 VRDistortionConstants& values)
411 ovrSizei texSize = { textureSize.width, textureSize.height };
412 ovrRecti eyePort = { { eyeViewport.x, eyeViewport.y }, { eyeViewport.width, eyeViewport.height } };
413 ovrVector2f scaleOut[2];
415 ovrHmd_GetRenderScaleAndOffset(mFOVPort[whichEye], texSize, eyePort, scaleOut);
417 values.eyeToSourceScaleAndOffset[0] = scaleOut[0].x;
418 values.eyeToSourceScaleAndOffset[1] = scaleOut[0].y;
419 values.eyeToSourceScaleAndOffset[2] = scaleOut[1].x;
420 values.eyeToSourceScaleAndOffset[3] = scaleOut[1].y;
422 // These values are in clip space [-1..1] range, but we're providing
423 // scaling in the 0..2 space for sanity.
425 // this is the destRect in clip space
426 float x0 = destRect.x / destViewport.width * 2.0 - 1.0;
427 float x1 = (destRect.x + destRect.width) / destViewport.width * 2.0 - 1.0;
429 float y0 = destRect.y / destViewport.height * 2.0 - 1.0;
430 float y1 = (destRect.y + destRect.height) / destViewport.height * 2.0 - 1.0;
432 // offset
433 values.destinationScaleAndOffset[0] = (x0+x1) / 2.0;
434 values.destinationScaleAndOffset[1] = (y0+y1) / 2.0;
435 // scale
436 values.destinationScaleAndOffset[2] = destRect.width / destViewport.width;
437 values.destinationScaleAndOffset[3] = destRect.height / destViewport.height;
440 bool
441 HMDInfoOculus::StartSensorTracking()
443 if (mStartCount == 0) {
444 bool ok = ovrHmd_ConfigureTracking(mHMD, ovrTrackingCap_Orientation | ovrTrackingCap_Position, 0);
445 if (!ok)
446 return false;
449 mStartCount++;
450 return true;
453 void
454 HMDInfoOculus::StopSensorTracking()
456 if (--mStartCount == 0) {
457 ovrHmd_ConfigureTracking(mHMD, 0, 0);
461 void
462 HMDInfoOculus::ZeroSensor()
464 ovrHmd_RecenterPose(mHMD);
467 VRHMDSensorState
468 HMDInfoOculus::GetSensorState(double timeOffset)
470 VRHMDSensorState result;
471 result.Clear();
473 // XXX this is the wrong time base for timeOffset; we need to figure out how to synchronize
474 // the Oculus time base and the browser one.
475 ovrTrackingState state = ovrHmd_GetTrackingState(mHMD, ovr_GetTimeInSeconds() + timeOffset);
476 ovrPoseStatef& pose(state.HeadPose);
478 result.timestamp = pose.TimeInSeconds;
480 if (state.StatusFlags & ovrStatus_OrientationTracked) {
481 result.flags |= State_Orientation;
483 result.orientation[0] = pose.ThePose.Orientation.x;
484 result.orientation[1] = pose.ThePose.Orientation.y;
485 result.orientation[2] = pose.ThePose.Orientation.z;
486 result.orientation[3] = pose.ThePose.Orientation.w;
488 result.angularVelocity[0] = pose.AngularVelocity.x;
489 result.angularVelocity[1] = pose.AngularVelocity.y;
490 result.angularVelocity[2] = pose.AngularVelocity.z;
492 result.angularAcceleration[0] = pose.AngularAcceleration.x;
493 result.angularAcceleration[1] = pose.AngularAcceleration.y;
494 result.angularAcceleration[2] = pose.AngularAcceleration.z;
497 if (state.StatusFlags & ovrStatus_PositionTracked) {
498 result.flags |= State_Position;
500 result.position[0] = pose.ThePose.Position.x;
501 result.position[1] = pose.ThePose.Position.y;
502 result.position[2] = pose.ThePose.Position.z;
504 result.linearVelocity[0] = pose.LinearVelocity.x;
505 result.linearVelocity[1] = pose.LinearVelocity.y;
506 result.linearVelocity[2] = pose.LinearVelocity.z;
508 result.linearAcceleration[0] = pose.LinearAcceleration.x;
509 result.linearAcceleration[1] = pose.LinearAcceleration.y;
510 result.linearAcceleration[2] = pose.LinearAcceleration.z;
513 return result;
516 namespace mozilla {
517 namespace gfx {
519 class VRHMDManagerOculusImpl {
520 public:
521 VRHMDManagerOculusImpl() : mOculusInitialized(false), mOculusPlatformInitialized(false)
524 bool PlatformInit();
525 bool Init();
526 void Destroy();
527 void GetOculusHMDs(nsTArray<nsRefPtr<VRHMDInfo> >& aHMDResult);
528 protected:
529 nsTArray<nsRefPtr<HMDInfoOculus>> mOculusHMDs;
530 bool mOculusInitialized;
531 bool mOculusPlatformInitialized;
534 } // namespace gfx
535 } // namespace mozilla
537 VRHMDManagerOculusImpl *VRHMDManagerOculus::mImpl = nullptr;
539 // These just forward to the Impl class, to have a non-static container for various
540 // objects.
542 bool
543 VRHMDManagerOculus::PlatformInit()
545 if (!mImpl) {
546 mImpl = new VRHMDManagerOculusImpl;
548 return mImpl->PlatformInit();
551 bool
552 VRHMDManagerOculus::Init()
554 if (!mImpl) {
555 mImpl = new VRHMDManagerOculusImpl;
557 return mImpl->Init();
560 void
561 VRHMDManagerOculus::GetOculusHMDs(nsTArray<nsRefPtr<VRHMDInfo>>& aHMDResult)
563 if (!mImpl) {
564 mImpl = new VRHMDManagerOculusImpl;
566 mImpl->GetOculusHMDs(aHMDResult);
569 void
570 VRHMDManagerOculus::Destroy()
572 if (!mImpl)
573 return;
574 mImpl->Destroy();
575 delete mImpl;
576 mImpl = nullptr;
579 bool
580 VRHMDManagerOculusImpl::PlatformInit()
582 if (mOculusPlatformInitialized)
583 return true;
585 if (!gfxPrefs::VREnabled())
586 return false;
588 if (!InitializeOculusCAPI())
589 return false;
591 bool ok = ovr_Initialize();
593 if (!ok)
594 return false;
596 mOculusPlatformInitialized = true;
597 return true;
600 bool
601 VRHMDManagerOculusImpl::Init()
603 if (mOculusInitialized)
604 return true;
606 if (!PlatformInit())
607 return false;
609 int count = ovrHmd_Detect();
611 for (int i = 0; i < count; ++i) {
612 ovrHmd hmd = ovrHmd_Create(i);
613 nsRefPtr<HMDInfoOculus> oc = new HMDInfoOculus(hmd);
614 mOculusHMDs.AppendElement(oc);
617 // VRAddTestDevices == 1: add test device only if no real devices present
618 // VRAddTestDevices == 2: add test device always
619 if ((count == 0 && gfxPrefs::VRAddTestDevices() == 1) ||
620 (gfxPrefs::VRAddTestDevices() == 2))
622 ovrHmd hmd = ovrHmd_CreateDebug(ovrHmd_DK2);
623 nsRefPtr<HMDInfoOculus> oc = new HMDInfoOculus(hmd);
624 mOculusHMDs.AppendElement(oc);
627 mOculusInitialized = true;
628 return true;
631 void
632 VRHMDManagerOculusImpl::Destroy()
634 if (!mOculusInitialized)
635 return;
637 for (size_t i = 0; i < mOculusHMDs.Length(); ++i) {
638 mOculusHMDs[i]->Destroy();
641 mOculusHMDs.Clear();
643 ovr_Shutdown();
644 mOculusInitialized = false;
647 void
648 VRHMDManagerOculusImpl::GetOculusHMDs(nsTArray<nsRefPtr<VRHMDInfo>>& aHMDResult)
650 Init();
651 for (size_t i = 0; i < mOculusHMDs.Length(); ++i) {
652 aHMDResult.AppendElement(mOculusHMDs[i]);