diff --git a/dom/vr/test/mochitest/VRSimulationDriver.js b/dom/vr/test/mochitest/VRSimulationDriver.js index f279d99953fb..6a1012df0067 100644 --- a/dom/vr/test/mochitest/VRSimulationDriver.js +++ b/dom/vr/test/mochitest/VRSimulationDriver.js @@ -6,10 +6,6 @@ var VRSimulationDriver = (function() { "use strict"; var AttachWebVRDisplay = function() { - if (vrMockDisplay) { - // Avoid creating multiple displays - return Promise.resolve(vrMockDisplay); - } var promise = VRServiceTest.attachVRDisplay("VRDisplayTest"); promise.then(function (display) { assert_true(display != null, "AttachWebVRDisplay should success."); diff --git a/dom/vr/test/mochitest/runVRTest.js b/dom/vr/test/mochitest/runVRTest.js index afb76f89e9a9..438c9f3a316f 100644 --- a/dom/vr/test/mochitest/runVRTest.js +++ b/dom/vr/test/mochitest/runVRTest.js @@ -1,9 +1,7 @@ function runVRTest(callback) { SpecialPowers.pushPrefEnv({"set" : [["dom.vr.puppet.enabled", true], ["dom.vr.require-gesture", false], - ["dom.vr.test.enabled", true], - ["dom.vr.display.enumerate.interval", 0], - ["dom.vr.controller.enumerate.interval", 0]]}, + ["dom.vr.test.enabled", true]]}, () => { VRServiceTest = navigator.requestVRServiceTest(); callback(); diff --git a/dom/vr/test/mochitest/test_vrController_displayId.html b/dom/vr/test/mochitest/test_vrController_displayId.html index 85f085057a0c..0f3e42d01845 100644 --- a/dom/vr/test/mochitest/test_vrController_displayId.html +++ b/dom/vr/test/mochitest/test_vrController_displayId.html @@ -38,14 +38,12 @@ function startTest() { promise_test((test) => { listenControllerEvents(); - return VRSimulationDriver.AttachWebVRDisplay().then(() => { - return navigator.getVRDisplays().then((displays) => { - vrDisplay = displays[0]; - assert_equals(displays.length, 1, "displays.length must be one after attach."); - assert_equals(displays[0].displayId, 1, "displayId must be one."); - addController(); - addController(); - }); + return navigator.getVRDisplays().then((displays) => { + vrDisplay = displays[0]; + assert_equals(displays.length, 1, "displays.length must be one after attach."); + assert_equals(displays[0].displayId, 1, "displayId must be one."); + addController(); + addController(); }); }, "Finish to add VRDisplay."); } diff --git a/dom/vr/test/mochitest/test_vrDisplay_canvas2d.html b/dom/vr/test/mochitest/test_vrDisplay_canvas2d.html index 2ebed1eef3d5..c4a5f5a07b84 100644 --- a/dom/vr/test/mochitest/test_vrDisplay_canvas2d.html +++ b/dom/vr/test/mochitest/test_vrDisplay_canvas2d.html @@ -6,7 +6,6 @@ - @@ -36,14 +35,12 @@ var img = document.createElement('img'); img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACw="; - return VRSimulationDriver.AttachWebVRDisplay().then(() => { - return navigator.getVRDisplays().then((displays) => { - assert_equals(displays.length, 1, "displays.length must be one after attach."); - vrDisplay = displays[0]; - var frameData = new VRFrameData(); - return vrDisplay.requestPresent([{source: canvas}]).then(() => { - requestPresentTest(); - }); + return navigator.getVRDisplays().then((displays) => { + assert_equals(displays.length, 1, "displays.length must be one after attach."); + vrDisplay = displays[0]; + var frameData = new VRFrameData(); + return vrDisplay.requestPresent([{source: canvas}]).then(() => { + requestPresentTest(); }); }); }, "Finish running WebVR Canvas2D test."); diff --git a/dom/vr/test/mochitest/test_vrDisplay_exitPresent.html b/dom/vr/test/mochitest/test_vrDisplay_exitPresent.html index cdce7d79045e..3edb2f0cc9e8 100644 --- a/dom/vr/test/mochitest/test_vrDisplay_exitPresent.html +++ b/dom/vr/test/mochitest/test_vrDisplay_exitPresent.html @@ -6,7 +6,6 @@ - @@ -18,29 +17,23 @@ }); } var initVRPresentation = function(content) { - return VRSimulationDriver.AttachWebVRDisplay().then(() => { - return content.navigator.getVRDisplays().then((displays) => { + return content.navigator.getVRDisplays().then((displays) => { content.vrDisplay = displays[0]; content.canvas = content.document.createElement("canvas"); content.canvas.id = "vrCanvas"; return content.vrDisplay.requestPresent([{source:content.canvas}]); }); - }); } function startTest() { var ifr1 = document.getElementById("iframe1"); var ifr2 = document.getElementById("iframe2"); var frame1 = ifr1.contentWindow; var frame2 = ifr2.contentWindow; - promise_test((test) => { - return VRSimulationDriver.AttachWebVRDisplay().then(() => { - return initVRPresentation(frame1).then(() => { - promise_test((test) => { - return promise_rejects(test, null, testExitPresentOnOtherIframe(frame2)); - }, "We cannot exit VR presentation established by another content, this promise is expected to be rejected.") - }); - }); - }, "Finish running WebVR exitPresent test."); + initVRPresentation(frame1).then(() => { + promise_test((test) => { + return promise_rejects(test, null, testExitPresentOnOtherIframe(frame2)); + }, "We cannot exist VR presentation established by another content, this promise is expected to be rejected.") + }); } runVRTest(startTest); diff --git a/dom/vr/test/reftest/VRSimulationDriver.js b/dom/vr/test/reftest/VRSimulationDriver.js index 971cdb8626fb..9ee139c0b2bf 100644 --- a/dom/vr/test/reftest/VRSimulationDriver.js +++ b/dom/vr/test/reftest/VRSimulationDriver.js @@ -6,10 +6,6 @@ var VRSimulationDriver = (function() { "use strict"; var AttachWebVRDisplay = function() { - if (vrMockDisplay) { - // Avoid creating multiple displays - return Promise.resolve(vrMockDisplay); - } var promise = VRServiceTest.attachVRDisplay("VRDisplayTest"); promise.then(function (display) { vrMockDisplay = display; diff --git a/dom/vr/test/reftest/reftest.list b/dom/vr/test/reftest/reftest.list index 07a9325306dc..102da84300f9 100644 --- a/dom/vr/test/reftest/reftest.list +++ b/dom/vr/test/reftest/reftest.list @@ -1,6 +1,6 @@ # WebVR Reftests # Please confirm there is no other VR display connected. Otherwise, VRPuppetDisplay can't be attached. -default-preferences pref(dom.vr.puppet.enabled,true) pref(dom.vr.test.enabled,true) pref(dom.vr.require-gesture,false) pref(dom.vr.puppet.submitframe,1) pref(dom.vr.display.rafMaxDuration,200) pref(dom.vr.display.enumerate.interval,0) pref(dom.vr.controller.enumerate.interval,0) +default-preferences pref(dom.vr.puppet.enabled,true) pref(dom.vr.test.enabled,true) pref(dom.vr.require-gesture,false) pref(dom.vr.puppet.submitframe,1) pref(dom.vr.display.rafMaxDuration,200) # VR SubmitFrame is only implemented for D3D11.1 and MacOSX now. # Our Windows 7 test machines don't support D3D11.1, so we run these tests on Windows 8+ only. diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index 21df904ca774..793dd88a993e 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -367,9 +367,6 @@ private: DECL_GFX_PREF(Live, "dom.vr.oculus.quit.timeout", VROculusQuitTimeout, int32_t, 30000); DECL_GFX_PREF(Once, "dom.vr.openvr.enabled", VROpenVREnabled, bool, false); DECL_GFX_PREF(Once, "dom.vr.osvr.enabled", VROSVREnabled, bool, false); - DECL_GFX_PREF(Live, "dom.vr.controller.enumerate.interval", VRControllerEnumerateInterval, int32_t, 1000); - DECL_GFX_PREF(Live, "dom.vr.display.enumerate.interval", VRDisplayEnumerateInterval, int32_t, 5000); - DECL_GFX_PREF(Live, "dom.vr.inactive.timeout", VRInactiveTimeout, int32_t, 5000); DECL_GFX_PREF(Live, "dom.vr.poseprediction.enabled", VRPosePredictionEnabled, bool, true); DECL_GFX_PREF(Live, "dom.vr.require-gesture", VRRequireGesture, bool, true); DECL_GFX_PREF(Live, "dom.vr.puppet.enabled", VRPuppetEnabled, bool, false); diff --git a/gfx/vr/VRDisplayHost.h b/gfx/vr/VRDisplayHost.h index 63ff99c73f84..509c761c3140 100644 --- a/gfx/vr/VRDisplayHost.h +++ b/gfx/vr/VRDisplayHost.h @@ -41,7 +41,7 @@ public: virtual void ZeroSensor() = 0; virtual void StartPresentation() = 0; virtual void StopPresentation() = 0; - void NotifyVSync(); + virtual void NotifyVSync(); void StartFrame(); void SubmitFrame(VRLayerParent* aLayer, diff --git a/gfx/vr/VRManager.cpp b/gfx/vr/VRManager.cpp index e22b63f81d05..123f65ce66d0 100644 --- a/gfx/vr/VRManager.cpp +++ b/gfx/vr/VRManager.cpp @@ -55,8 +55,7 @@ VRManager::ManagerInit() VRManager::VRManager() : mInitialized(false) - , mVRDisplaysRequested(false) - , mVRControllersRequested(false) + , mVRTestSystemCreated(false) { MOZ_COUNT_CTOR(VRManager); MOZ_ASSERT(sVRManagerSingleton == nullptr); @@ -175,8 +174,12 @@ VRManager::RemoveVRManagerParent(VRManagerParent* aVRManagerParent) } void -VRManager::UpdateRequestedDevices() +VRManager::NotifyVsync(const TimeStamp& aVsyncTimestamp) { + MOZ_ASSERT(VRListenerThreadHolder::IsInVRListenerThread()); + const double kVRDisplayRefreshMaxDuration = 5000; // milliseconds + const double kVRDisplayInactiveMaxDuration = 30000; // milliseconds + bool bHaveEventListener = false; bool bHaveControllerListener = false; @@ -186,55 +189,61 @@ VRManager::UpdateRequestedDevices() bHaveControllerListener |= vmp->HaveControllerListener(); } - mVRDisplaysRequested = bHaveEventListener; - // We only currently allow controllers to be used when - // also activating a VR display - mVRControllersRequested = mVRDisplaysRequested && bHaveControllerListener; -} - -/** - * VRManager::NotifyVsync must be called on every 2d vsync (usually at 60hz). - * This must be called even when no WebVR site is active. - * If we don't have a 2d display attached to the system, we can call this - * at the VR display's native refresh rate. - **/ -void -VRManager::NotifyVsync(const TimeStamp& aVsyncTimestamp) -{ - MOZ_ASSERT(VRListenerThreadHolder::IsInVRListenerThread()); - UpdateRequestedDevices(); - - for (const auto& manager : mManagers) { - manager->NotifyVSync(); + // VRDisplayHost::NotifyVSync may modify mVRDisplays, so we iterate + // through a local copy here. + nsTArray> displays; + for (auto iter = mVRDisplays.Iter(); !iter.Done(); iter.Next()) { + displays.AppendElement(iter.UserData()); + } + for (const auto& display: displays) { + display->NotifyVSync(); } - // We must continually refresh the VR display enumeration to check - // for events that we must fire such as Window.onvrdisplayconnect - // Note that enumeration itself may activate display hardware, such - // as Oculus, so we only do this when we know we are displaying content - // that is looking for VR displays. - RefreshVRDisplays(); + if (bHaveEventListener) { + // If content has set an EventHandler to be notified of VR display events + // we must continually refresh the VR display enumeration to check + // for events that we must fire such as Window.onvrdisplayconnect + // Note that enumeration itself may activate display hardware, such + // as Oculus, so we only do this when we know we are displaying content + // that is looking for VR displays. + if (mLastRefreshTime.IsNull()) { + // This is the first vsync, must refresh VR displays + RefreshVRDisplays(); + if (bHaveControllerListener) { + RefreshVRControllers(); + } + mLastRefreshTime = TimeStamp::Now(); + } else { + // We don't have to do this every frame, so check if we + // have refreshed recently. + TimeDuration duration = TimeStamp::Now() - mLastRefreshTime; + if (duration.ToMilliseconds() > kVRDisplayRefreshMaxDuration) { + RefreshVRDisplays(); + if (bHaveControllerListener) { + RefreshVRControllers(); + } + mLastRefreshTime = TimeStamp::Now(); + } + } - // Update state and enumeration of VR controllers - RefreshVRControllers(); + if (bHaveControllerListener) { + for (const auto& manager: mManagers) { + if (!manager->GetIsPresenting()) { + manager->HandleInput(); + } + } + } + } - CheckForInactiveTimeout(); -} - -void -VRManager::CheckForInactiveTimeout() -{ // Shut down the VR devices when not in use - if (mVRDisplaysRequested || mVRControllersRequested) { + if (bHaveEventListener || bHaveControllerListener) { // We are using a VR device, keep it alive mLastActiveTime = TimeStamp::Now(); - } - else if (mLastActiveTime.IsNull()) { + } else if (mLastActiveTime.IsNull()) { Shutdown(); - } - else { + } else { TimeDuration duration = TimeStamp::Now() - mLastActiveTime; - if (duration.ToMilliseconds() > gfxPrefs::VRInactiveTimeout()) { + if (duration.ToMilliseconds() > kVRDisplayInactiveMaxDuration) { Shutdown(); } } @@ -258,80 +267,26 @@ VRManager::NotifyVRVsync(const uint32_t& aDisplayID) RefreshVRDisplays(); } -void -VRManager::EnumerateVRDisplays() -{ - /** - * Throttle the rate of enumeration to the interval set in - * VRDisplayEnumerateInterval - */ - if (!mLastDisplayEnumerationTime.IsNull()) { - TimeDuration duration = TimeStamp::Now() - mLastDisplayEnumerationTime; - if (duration.ToMilliseconds() < gfxPrefs::VRDisplayEnumerateInterval()) { - return; - } - } - - /** - * Any VRSystemManager instance may request that no enumeration - * should occur, including enumeration from other VRSystemManager - * instances. - */ - for (const auto& manager : mManagers) { - if (manager->ShouldInhibitEnumeration()) { - return; - } - } - - /** - * If we get this far, don't try again until - * the VRDisplayEnumerateInterval elapses - */ - mLastDisplayEnumerationTime = TimeStamp::Now(); - - /** - * VRSystemManagers are inserted into mManagers in - * a strict order of priority. The managers for the - * most device-specialized API's will have a chance - * to enumerate devices before the more generic - * device-agnostic APIs. - */ - for (const auto& manager : mManagers) { - manager->Enumerate(); - /** - * After a VRSystemManager::Enumerate is called, it may request - * that further enumeration should stop. This can be used to prevent - * erraneous redundant enumeration of the same HMD by multiple managers. - * XXX - Perhaps there will be a better way to detect duplicate displays - * in the future. - */ - if (manager->ShouldInhibitEnumeration()) { - return; - } - } -} - void VRManager::RefreshVRDisplays(bool aMustDispatch) { - /** - * If we aren't viewing WebVR content, don't enumerate - * new hardware, as it will cause some devices to power on - * or interrupt other VR activities. - */ - if (mVRDisplaysRequested || aMustDispatch) { - EnumerateVRDisplays(); - } - - /** - * VRSystemManager::GetHMDs will not activate new hardware - * or result in interruption of other VR activities. - * We can call it even when suppressing enumeration to get - * the already-enumerated displays. - */ nsTArray > displays; - for (const auto& manager: mManagers) { - manager->GetHMDs(displays); + + /** We don't wish to enumerate the same display from multiple managers, + * so stop as soon as we get a display. + * It is still possible to get multiple displays from a single manager, + * but do not wish to mix-and-match for risk of reporting a duplicate. + * + * XXX - Perhaps there will be a better way to detect duplicate displays + * in the future. + */ + for (uint32_t i = 0; i < mManagers.Length() && displays.Length() == 0; ++i) { + if (mManagers[i]->GetHMDs(displays)) { + // GetHMDs returns true to indicate that no further enumeration from + // other managers should be performed. This prevents erraneous + // redundant enumeration of the same HMD by multiple managers. + break; + } } bool displayInfoChanged = false; @@ -428,10 +383,10 @@ VRManager::GetVRControllerInfo(nsTArray& aControllerInfo) void VRManager::RefreshVRControllers() { - ScanForControllers(); - nsTArray> controllers; + ScanForControllers(); + for (uint32_t i = 0; i < mManagers.Length() && controllers.Length() == 0; ++i) { mManagers[i]->GetControllers(controllers); @@ -464,25 +419,9 @@ VRManager::RefreshVRControllers() void VRManager::ScanForControllers() { - // We don't have to do this every frame, so check if we - // have enumerated recently - if (!mLastControllerEnumerationTime.IsNull()) { - TimeDuration duration = TimeStamp::Now() - mLastControllerEnumerationTime; - if (duration.ToMilliseconds() < gfxPrefs::VRControllerEnumerateInterval()) { - return; - } - } - - // Only enumerate controllers once we need them - if (!mVRControllersRequested) { - return; - } - for (uint32_t i = 0; i < mManagers.Length(); ++i) { mManagers[i]->ScanForControllers(); } - - mLastControllerEnumerationTime = TimeStamp::Now(); } void @@ -497,20 +436,15 @@ VRManager::RemoveControllers() void VRManager::CreateVRTestSystem() { - if (mPuppetManager) { - mPuppetManager->ClearTestDisplays(); + if (mVRTestSystemCreated) { return; } - mPuppetManager = VRSystemManagerPuppet::Create(); - mManagers.AppendElement(mPuppetManager); -} - -VRSystemManagerPuppet* -VRManager::GetPuppetManager() -{ - MOZ_ASSERT(mPuppetManager); - return mPuppetManager; + RefPtr mgr = VRSystemManagerPuppet::Create(); + if (mgr) { + mManagers.AppendElement(mgr); + mVRTestSystemCreated = true; + } } template diff --git a/gfx/vr/VRManager.h b/gfx/vr/VRManager.h index 062b46ca092c..7c79922ed442 100644 --- a/gfx/vr/VRManager.h +++ b/gfx/vr/VRManager.h @@ -23,7 +23,6 @@ namespace gfx { class VRLayerParent; class VRManagerParent; class VRDisplayHost; -class VRSystemManagerPuppet; class VRManager { @@ -48,8 +47,6 @@ public: RefPtr GetController(const uint32_t& aControllerID); void GetVRControllerInfo(nsTArray& aControllerInfo); void CreateVRTestSystem(); - VRSystemManagerPuppet* GetPuppetManager(); - void VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex, double aIntensity, double aDuration, uint32_t aPromiseID); void StopVibrateHaptic(uint32_t aControllerIdx); @@ -67,9 +64,6 @@ private: void Shutdown(); void DispatchVRDisplayInfoUpdate(); - void UpdateRequestedDevices(); - void EnumerateVRDisplays(); - void CheckForInactiveTimeout(); typedef nsTHashtable> VRManagerParentSet; VRManagerParentSet mVRManagerParents; @@ -85,12 +79,9 @@ private: Atomic mInitialized; - TimeStamp mLastControllerEnumerationTime; - TimeStamp mLastDisplayEnumerationTime; + TimeStamp mLastRefreshTime; TimeStamp mLastActiveTime; - RefPtr mPuppetManager; - bool mVRDisplaysRequested; - bool mVRControllersRequested; + bool mVRTestSystemCreated; }; } // namespace gfx diff --git a/gfx/vr/gfxVR.cpp b/gfx/vr/gfxVR.cpp index da6054b591c8..849adc10ff62 100644 --- a/gfx/vr/gfxVR.cpp +++ b/gfx/vr/gfxVR.cpp @@ -9,7 +9,6 @@ #include "gfxVR.h" #include "mozilla/dom/GamepadEventTypes.h" #include "mozilla/dom/GamepadBinding.h" -#include "VRDisplayHost.h" #ifndef M_PI # define M_PI 3.14159265358979323846 @@ -33,58 +32,6 @@ VRSystemManager::AllocateControllerID() return ++sControllerBase; } -/** - * VRSystemManager::NotifyVsync must be called even when a WebVR site is - * not active, in order to poll for respond to VR Platform API requests. - * This should be called very often, ideally once per frame. - * VRSystemManager::Refresh will not activate VR hardware or - * initialize VR runtimes that have not already been activated. - */ -void -VRSystemManager::NotifyVSync() -{ - // VRDisplayHost::NotifyVSync may modify mVRDisplays, so we iterate - // through a local copy here. - nsTArray> displays; - GetHMDs(displays); - for (const auto& display : displays) { - display->NotifyVSync(); - } - - // Ensure that the controller state is updated at least - // on every 2d display VSync when not in a VR presentation. - if (!GetIsPresenting()) { - HandleInput(); - } -} - -/** - * VRSystemManager::GetHMDs must not be called unless - * VRSystemManager::ShouldInhibitEnumeration is called - * on all VRSystemManager instances and they all return - * false. - * - * This is used to ensure that VR devices that can be - * enumerated by multiple API's are only enumerated by - * one API. - * - * GetHMDs is called for the most specific API - * (ie. Oculus SDK) first before calling GetHMDs on - * more generic api's (ie. OpenVR) to ensure that a device - * is accessed using the API most optimized for it. - * - * ShouldInhibitEnumeration may also be used to prevent - * devices from jumping to other API's when they are - * intentionally ignored, such as when responding to - * requests by the VR platform to unload the libraries - * for runtime software updates. - */ -bool -VRSystemManager::ShouldInhibitEnumeration() -{ - return false; -} - Matrix4x4 VRFieldOfView::ConstructProjectionMatrix(float zNear, float zFar, bool rightHanded) const diff --git a/gfx/vr/gfxVR.h b/gfx/vr/gfxVR.h index 48da76bc1461..7f71836ba0da 100644 --- a/gfx/vr/gfxVR.h +++ b/gfx/vr/gfxVR.h @@ -347,10 +347,7 @@ public: virtual void Destroy() = 0; virtual void Shutdown() = 0; - virtual void Enumerate() = 0; - virtual void NotifyVSync(); - virtual bool ShouldInhibitEnumeration(); - virtual void GetHMDs(nsTArray>& aHMDResult) = 0; + virtual bool GetHMDs(nsTArray>& aHMDResult) = 0; virtual bool GetIsPresenting() = 0; virtual void HandleInput() = 0; virtual void GetControllers(nsTArray>& aControllerResult) = 0; diff --git a/gfx/vr/gfxVRGVR.cpp b/gfx/vr/gfxVRGVR.cpp index 28f65214d749..a099947b03e9 100644 --- a/gfx/vr/gfxVRGVR.cpp +++ b/gfx/vr/gfxVRGVR.cpp @@ -340,6 +340,12 @@ VRDisplayGVR::SubmitFrame(const mozilla::layers::EGLImageDescriptor* aDescriptor return true; } +void +VRDisplayGVR::NotifyVSync() +{ + VRDisplayHost::NotifyVSync(); +} + static void FillMatrix(gfx::Matrix4x4 &target, const gvr_mat4f& source) { @@ -706,40 +712,19 @@ VRSystemManagerGVR::Shutdown() } -void -VRSystemManagerGVR::Enumerate() +bool +VRSystemManagerGVR::GetHMDs(nsTArray >& aHMDResult) { if (!GeckoVRManager::IsGVRPresent()) { - return; + return false; } if (!mGVRHMD) { mGVRHMD = new VRDisplayGVR(); } -} -bool -VRSystemManagerGVR::ShouldInhibitEnumeration() -{ - if (VRSystemManager::ShouldInhibitEnumeration()) { - return true; - } - if (mGVRHMD) { - // When we find an a VR device, don't - // allow any further enumeration as it - // may get picked up redundantly by other - // API's. - return true; - } - return false; -} - -void -VRSystemManagerGVR::GetHMDs(nsTArray>& aHMDResult) -{ - if (mGVRHMD) { - aHMDResult.AppendElement(mGVRHMD); - } + aHMDResult.AppendElement(mGVRHMD); + return true; } bool diff --git a/gfx/vr/gfxVRGVR.h b/gfx/vr/gfxVRGVR.h index eec3306909b2..175489db4857 100644 --- a/gfx/vr/gfxVRGVR.h +++ b/gfx/vr/gfxVRGVR.h @@ -60,6 +60,7 @@ public: bool SubmitFrame(const mozilla::layers::EGLImageDescriptor* aDescriptor, const gfx::Rect& aLeftEyeRect, const gfx::Rect& aRightEyeRect) override; + void NotifyVSync() override; protected: virtual VRHMDSensorState GetSensorState() override; // END VRDisplayHost interface @@ -104,9 +105,7 @@ public: void Destroy() override; void Shutdown() override; - void Enumerate() override; - bool ShouldInhibitEnumeration() override; - void GetHMDs(nsTArray>& aHMDResult) override; + bool GetHMDs(nsTArray >& aHMDResult) override; bool GetIsPresenting() override; void HandleInput() override; void GetControllers(nsTArray>& diff --git a/gfx/vr/gfxVROSVR.cpp b/gfx/vr/gfxVROSVR.cpp index 053fc59f7480..c76a302c736b 100644 --- a/gfx/vr/gfxVROSVR.cpp +++ b/gfx/vr/gfxVROSVR.cpp @@ -550,51 +550,25 @@ VRSystemManagerOSVR::Shutdown() osvr_ClientShutdown(m_ctx); } -void -VRSystemManagerOSVR::NotifyVSync() -{ - VRSystemManager::NotifyVSync(); - - // TODO - Check for device disconnection or other OSVR events -} - -void -VRSystemManagerOSVR::Enumerate() +bool +VRSystemManagerOSVR::GetHMDs(nsTArray>& aHMDResult) { // make sure context, interface and display are initialized CheckOSVRStatus(); if (!Init()) { - return; + return false; } mHMDInfo = new VRDisplayOSVR(&m_ctx, &m_iface, &m_display); -} -bool -VRSystemManagerOSVR::ShouldInhibitEnumeration() -{ - if (VRSystemManager::ShouldInhibitEnumeration()) { - return true; - } if (mHMDInfo) { - // When we find an a VR device, don't - // allow any further enumeration as it - // may get picked up redundantly by other - // API's. + aHMDResult.AppendElement(mHMDInfo); return true; } return false; } -void -VRSystemManagerOSVR::GetHMDs(nsTArray>& aHMDResult) -{ - if (mHMDInfo) { - aHMDResult.AppendElement(mHMDInfo); - } -} - bool VRSystemManagerOSVR::GetIsPresenting() { diff --git a/gfx/vr/gfxVROSVR.h b/gfx/vr/gfxVROSVR.h index a79d7e659733..3b70622aa39d 100644 --- a/gfx/vr/gfxVROSVR.h +++ b/gfx/vr/gfxVROSVR.h @@ -80,10 +80,7 @@ public: static already_AddRefed Create(); virtual void Destroy() override; virtual void Shutdown() override; - virtual void NotifyVSync() override; - virtual void Enumerate() override; - virtual bool ShouldInhibitEnumeration() override; - virtual void GetHMDs(nsTArray>& aHMDResult) override; + virtual bool GetHMDs(nsTArray>& aHMDResult) override; virtual bool GetIsPresenting() override; virtual void HandleInput() override; virtual void GetControllers(nsTArray>& diff --git a/gfx/vr/gfxVROculus.cpp b/gfx/vr/gfxVROculus.cpp index 6f266d834bda..c9cdfb6563a3 100644 --- a/gfx/vr/gfxVROculus.cpp +++ b/gfx/vr/gfxVROculus.cpp @@ -204,11 +204,8 @@ VROculusSession::VROculusSession() , mSession(nullptr) , mInitFlags((ovrInitFlags)0) , mTextureSet(nullptr) - , mRequestPresentation(false) - , mRequestTracking(false) + , mPresenting(false) , mDrawBlack(false) - , mIsConnected(false) - , mIsMounted(false) { } @@ -222,47 +219,26 @@ VROculusSession::Get() bool VROculusSession::IsTrackingReady() const { - // We should return true only if the HMD is connected and we - // are ready for tracking - MOZ_ASSERT(!mIsConnected || mSession); - return mIsConnected; + return mSession != nullptr; } bool -VROculusSession::IsPresentationReady() const +VROculusSession::IsRenderReady() const { return !mRenderTargets.IsEmpty(); } -bool -VROculusSession::IsMounted() const -{ - return mIsMounted; -} - void VROculusSession::StopTracking() { - if (mRequestTracking) { - mRequestTracking = false; - Refresh(); - } -} - -void -VROculusSession::StartTracking() -{ - if (!mRequestTracking) { - mRequestTracking = true; - Refresh(); - } + Uninitialize(true); } void VROculusSession::StartPresentation(const IntSize& aSize) { - if (!mRequestPresentation) { - mRequestPresentation = true; + if (!mPresenting) { + mPresenting = true; mTelemetry.Clear(); mTelemetry.mPresentationStart = TimeStamp::Now(); @@ -282,9 +258,9 @@ VROculusSession::StartPresentation(const IntSize& aSize) void VROculusSession::StopPresentation() { - if (mRequestPresentation) { + if (mPresenting) { mLastPresentationEnd = TimeStamp::Now(); - mRequestPresentation = false; + mPresenting = false; const TimeDuration duration = mLastPresentationEnd - mTelemetry.mPresentationStart; Telemetry::Accumulate(Telemetry::WEBVR_USERS_VIEW_IN, 1); @@ -339,8 +315,6 @@ VROculusSession::StopSession() { if (mSession) { ovr_Destroy(mSession); - mIsConnected = false; - mIsMounted = false; mSession = nullptr; } } @@ -363,14 +337,9 @@ VROculusSession::Refresh(bool aForceRefresh) return; } - if (!mRequestTracking) { - Uninitialize(true); - return; - } - ovrInitFlags flags = (ovrInitFlags)(ovrInit_RequestVersion | ovrInit_MixedRendering); bool bInvisible = true; - if (mRequestPresentation) { + if (mPresenting) { bInvisible = false; } else if (!mLastPresentationEnd.IsNull()) { TimeDuration duration = TimeStamp::Now() - mLastPresentationEnd; @@ -415,25 +384,15 @@ VROculusSession::Refresh(bool aForceRefresh) Uninitialize(false); } - if(!Initialize(flags)) { - // If we fail to initialize, ensure the Oculus libraries - // are unloaded, as we can't poll for ovrSessionStatus::ShouldQuit - // without an active ovrSession. - Uninitialize(true); - } + Initialize(flags); if (mSession) { ovrSessionStatus status; if (OVR_SUCCESS(ovr_GetSessionStatus(mSession, &status))) { - mIsConnected = status.HmdPresent; - mIsMounted = status.HmdMounted; if (status.ShouldQuit) { mLastShouldQuit = TimeStamp::Now(); Uninitialize(true); } - } else { - mIsConnected = false; - mIsMounted = false; } } } @@ -478,7 +437,7 @@ VROculusSession::Initialize(ovrInitFlags aFlags) bool VROculusSession::StartRendering() { - if (!mRequestPresentation) { + if (!mPresenting) { // Nothing to do if we aren't presenting return true; } @@ -1014,7 +973,7 @@ VRDisplayOculus::StartPresentation() return; } mSession->StartPresentation(IntSize(mDisplayInfo.mEyeResolution.width * 2, mDisplayInfo.mEyeResolution.height)); - if (!mSession->IsPresentationReady()) { + if (!mSession->IsRenderReady()) { return; } @@ -1144,7 +1103,7 @@ VRDisplayOculus::SubmitFrame(ID3D11Texture2D* aSource, return false; } - if (!mSession->IsPresentationReady()) { + if (!mSession->IsRenderReady()) { return false; } /** @@ -1289,10 +1248,18 @@ VRDisplayOculus::SubmitFrame(ID3D11Texture2D* aSource, } void -VRDisplayOculus::Refresh() +VRDisplayOculus::NotifyVSync() { - mDisplayInfo.mIsConnected = mSession->IsTrackingReady(); - mDisplayInfo.mIsMounted = mSession->IsMounted(); + mSession->Refresh(); + if (mSession->IsTrackingReady()) { + ovrSessionStatus sessionStatus; + ovrResult ovr = ovr_GetSessionStatus(mSession->Get(), &sessionStatus); + mDisplayInfo.mIsConnected = (ovr == ovrSuccess && sessionStatus.HmdPresent); + } else { + mDisplayInfo.mIsConnected = false; + } + + VRDisplayHost::NotifyVSync(); } VRControllerOculus::VRControllerOculus(dom::GamepadHand aHand, uint32_t aDisplayID) @@ -1550,66 +1517,37 @@ VRSystemManagerOculus::Shutdown() mDisplay = nullptr; } -void -VRSystemManagerOculus::NotifyVSync() -{ - VRSystemManager::NotifyVSync(); - if (!mSession) { - return; - } - mSession->Refresh(); - if (mDisplay) { - mDisplay->Refresh(); - } - // Detect disconnection - if (!mSession->IsTrackingReady()) { - // No HMD connected - mDisplay = nullptr; - } -} - bool -VRSystemManagerOculus::ShouldInhibitEnumeration() -{ - if (VRSystemManager::ShouldInhibitEnumeration()) { - return true; - } - if (mDisplay) { - // When we find an Oculus VR device, don't - // allow any further enumeration as it - // may get picked up redundantly by other - // API's such as OpenVR. - return true; - } - if (mSession && mSession->IsQuitTimeoutActive()) { - // When we are responding to ShouldQuit, we return true here - // to prevent further enumeration by other VRSystemManager's such as - // VRSystemManagerOpenVR which would also enumerate the connected Oculus - // HMD, resulting in interference with the Oculus runtime software updates. - return true; - } - return false; -} - -void -VRSystemManagerOculus::Enumerate() +VRSystemManagerOculus::GetHMDs(nsTArray>& aHMDResult) { if (!mSession) { mSession = new VROculusSession(); } - mSession->StartTracking(); - if (mDisplay == nullptr && mSession->IsTrackingReady()) { + mSession->Refresh(); + if (mSession->IsQuitTimeoutActive()) { + // We have responded to a ShouldQuit flag set by the Oculus runtime + // and are waiting for a timeout duration to elapse before allowing + // re-initialization of the Oculus OVR lib. We return true in this case + // to prevent further enumeration by other VRSystemManager's such as + // VRSystemManagerOpenVR which would also enumerate the connected Oculus + // HMD, resulting in interference with the Oculus runtime software updates. + mDisplay = nullptr; + return true; + } + + if (!mSession->IsTrackingReady()) { + // No HMD connected. + mDisplay = nullptr; + } else if (mDisplay == nullptr) { // HMD Detected mDisplay = new VRDisplayOculus(mSession); } -} -void -VRSystemManagerOculus::GetHMDs(nsTArray>& aHMDResult) -{ if (mDisplay) { aHMDResult.AppendElement(mDisplay); + return true; } + return false; } bool diff --git a/gfx/vr/gfxVROculus.h b/gfx/vr/gfxVROculus.h index e77e054ba359..8e3f0812a721 100644 --- a/gfx/vr/gfxVROculus.h +++ b/gfx/vr/gfxVROculus.h @@ -42,14 +42,12 @@ class VROculusSession public: VROculusSession(); void Refresh(bool aForceRefresh = false); - void StartTracking(); - void StopTracking(); bool IsTrackingReady() const; + bool IsRenderReady() const; + ovrSession Get(); void StartPresentation(const IntSize& aSize); void StopPresentation(); - bool IsPresentationReady() const; - bool IsMounted() const; - ovrSession Get(); + void StopTracking(); bool IsQuitTimeoutActive(); already_AddRefed GetNextRenderTarget(); ovrTextureSwapChain GetSwapChain(); @@ -67,12 +65,8 @@ private: // The timestamp of the last ending presentation TimeStamp mLastPresentationEnd; VRTelemetry mTelemetry; - bool mRequestPresentation; - bool mRequestTracking; - bool mTracking; + bool mPresenting; bool mDrawBlack; - bool mIsConnected; - bool mIsMounted; ~VROculusSession(); void Uninitialize(bool aUnloadLib); @@ -90,6 +84,7 @@ private: class VRDisplayOculus : public VRDisplayHost { public: + virtual void NotifyVSync() override; void ZeroSensor() override; protected: @@ -105,7 +100,6 @@ protected: public: explicit VRDisplayOculus(VROculusSession* aSession); void Destroy(); - void Refresh(); protected: virtual ~VRDisplayOculus(); @@ -182,10 +176,7 @@ public: static already_AddRefed Create(); virtual void Destroy() override; virtual void Shutdown() override; - virtual void Enumerate() override; - virtual void NotifyVSync() override; - virtual bool ShouldInhibitEnumeration() override; - virtual void GetHMDs(nsTArray >& aHMDResult) override; + virtual bool GetHMDs(nsTArray >& aHMDResult) override; virtual bool GetIsPresenting() override; virtual void HandleInput() override; virtual void GetControllers(nsTArray>& diff --git a/gfx/vr/gfxVROpenVR.cpp b/gfx/vr/gfxVROpenVR.cpp index 009504f93498..c7a43df1050b 100644 --- a/gfx/vr/gfxVROpenVR.cpp +++ b/gfx/vr/gfxVROpenVR.cpp @@ -202,10 +202,8 @@ VRDisplayOpenVR::GetIsHmdPresent() } void -VRDisplayOpenVR::Refresh() +VRDisplayOpenVR::PollEvents() { - mIsHmdPresent = ::vr::VR_IsHmdPresent(); - ::vr::VREvent_t event; while (mVRSystem && mVRSystem->PollNextEvent(&event, sizeof(event))) { switch (event.eventType) { @@ -246,6 +244,8 @@ VRDisplayOpenVR::Refresh() VRHMDSensorState VRDisplayOpenVR::GetSensorState() { + PollEvents(); + const uint32_t posesSize = ::vr::k_unTrackedDeviceIndex_Hmd + 1; ::vr::TrackedDevicePose_t poses[posesSize]; // Note: We *must* call WaitGetPoses in order for any rendering to happen at all. @@ -422,6 +422,17 @@ VRDisplayOpenVR::SubmitFrame(MacIOSurface* aMacIOSurface, #endif +void +VRDisplayOpenVR::NotifyVSync() +{ + // We check if HMD is available once per frame. + mIsHmdPresent = ::vr::VR_IsHmdPresent(); + // Make sure we respond to OpenVR events even when not presenting + PollEvents(); + + VRDisplayHost::NotifyVSync(); +} + VRControllerOpenVR::VRControllerOpenVR(dom::GamepadHand aHand, uint32_t aDisplayID, uint32_t aNumButtons, uint32_t aNumTriggers, uint32_t aNumAxes, const nsCString& aId) @@ -622,87 +633,50 @@ VRSystemManagerOpenVR::Shutdown() mVRSystem = nullptr; } -void -VRSystemManagerOpenVR::NotifyVSync() +bool +VRSystemManagerOpenVR::GetHMDs(nsTArray>& aHMDResult) { - VRSystemManager::NotifyVSync(); - - // Avoid doing anything unless we have already - // successfully enumerated and loaded the OpenVR - // runtime. - if (mVRSystem == nullptr) { - return; - } - - if (mOpenVRHMD) { - mOpenVRHMD->Refresh(); - if (!mOpenVRHMD->GetIsHmdPresent()) { - // OpenVR runtime could be quit accidentally - // or a device could be disconnected. - // We free up resources and must re-initialize - // if a device is detected again later. - mOpenVRHMD = nullptr; - mVRSystem = nullptr; - } - } -} - -void -VRSystemManagerOpenVR::Enumerate() -{ - if (mOpenVRHMD == nullptr && ::vr::VR_IsHmdPresent()) { + if (!::vr::VR_IsHmdPresent() || + (mOpenVRHMD && !mOpenVRHMD->GetIsHmdPresent())) { + // OpenVR runtime could be quit accidentally, + // and we make it re-initialize. + mOpenVRHMD = nullptr; + mVRSystem = nullptr; + } else if (mOpenVRHMD == nullptr) { ::vr::HmdError err; ::vr::VR_Init(&err, ::vr::EVRApplicationType::VRApplication_Scene); if (err) { - return; + return false; } ::vr::IVRSystem *system = (::vr::IVRSystem *)::vr::VR_GetGenericInterface(::vr::IVRSystem_Version, &err); if (err || !system) { ::vr::VR_Shutdown(); - return; + return false; } ::vr::IVRChaperone *chaperone = (::vr::IVRChaperone *)::vr::VR_GetGenericInterface(::vr::IVRChaperone_Version, &err); if (err || !chaperone) { ::vr::VR_Shutdown(); - return; + return false; } ::vr::IVRCompositor *compositor = (::vr::IVRCompositor*)::vr::VR_GetGenericInterface(::vr::IVRCompositor_Version, &err); if (err || !compositor) { ::vr::VR_Shutdown(); - return; + return false; } mVRSystem = system; mOpenVRHMD = new VRDisplayOpenVR(system, chaperone, compositor); } -} -bool -VRSystemManagerOpenVR::ShouldInhibitEnumeration() -{ - if (VRSystemManager::ShouldInhibitEnumeration()) { - return true; - } if (mOpenVRHMD) { - // When we find an a VR device, don't - // allow any further enumeration as it - // may get picked up redundantly by other - // API's. + aHMDResult.AppendElement(mOpenVRHMD); return true; } return false; } -void -VRSystemManagerOpenVR::GetHMDs(nsTArray>& aHMDResult) -{ - if (mOpenVRHMD) { - aHMDResult.AppendElement(mOpenVRHMD); - } -} - bool VRSystemManagerOpenVR::GetIsPresenting() { diff --git a/gfx/vr/gfxVROpenVR.h b/gfx/vr/gfxVROpenVR.h index 2bb310a697ed..f632c4266852 100644 --- a/gfx/vr/gfxVROpenVR.h +++ b/gfx/vr/gfxVROpenVR.h @@ -30,6 +30,7 @@ namespace impl { class VRDisplayOpenVR : public VRDisplayHost { public: + virtual void NotifyVSync() override; void ZeroSensor() override; bool GetIsHmdPresent(); @@ -53,7 +54,7 @@ public: explicit VRDisplayOpenVR(::vr::IVRSystem *aVRSystem, ::vr::IVRChaperone *aVRChaperone, ::vr::IVRCompositor *aVRCompositor); - void Refresh(); + protected: virtual ~VRDisplayOpenVR(); void Destroy(); @@ -69,6 +70,7 @@ protected: void UpdateStageParameters(); void UpdateEyeParameters(gfx::Matrix4x4* aHeadToEyeTransforms = nullptr); + void PollEvents(); bool SubmitFrame(void* aTextureHandle, ::vr::ETextureType aTextureType, const IntSize& aSize, @@ -125,10 +127,7 @@ public: virtual void Destroy() override; virtual void Shutdown() override; - virtual void NotifyVSync() override; - virtual void Enumerate() override; - virtual bool ShouldInhibitEnumeration() override; - virtual void GetHMDs(nsTArray>& aHMDResult) override; + virtual bool GetHMDs(nsTArray >& aHMDResult) override; virtual bool GetIsPresenting() override; virtual void HandleInput() override; virtual void GetControllers(nsTArray>& diff --git a/gfx/vr/gfxVRPuppet.cpp b/gfx/vr/gfxVRPuppet.cpp index 8d5a6bae0199..6404f2c0ec65 100644 --- a/gfx/vr/gfxVRPuppet.cpp +++ b/gfx/vr/gfxVRPuppet.cpp @@ -566,10 +566,12 @@ VRDisplayPuppet::SubmitFrame(const mozilla::layers::EGLImageDescriptor* aDescrip #endif void -VRDisplayPuppet::Refresh() +VRDisplayPuppet::NotifyVSync() { - // We update mIsConneced once per refresh. + // We update mIsConneced once per frame. mDisplayInfo.mIsConnected = true; + + VRDisplayHost::NotifyVSync(); } VRControllerPuppet::VRControllerPuppet(dom::GamepadHand aHand, uint32_t aDisplayID) @@ -675,9 +677,6 @@ VRControllerPuppet::SetAxisMove(uint32_t aAxis, float aValue) } VRSystemManagerPuppet::VRSystemManagerPuppet() - : mPuppetDisplayCount(0) - , mPuppetDisplayInfo{} - , mPuppetDisplaySensorState{} { } @@ -701,119 +700,27 @@ VRSystemManagerPuppet::Destroy() void VRSystemManagerPuppet::Shutdown() { - mPuppetHMDs.Clear(); + mPuppetHMD = nullptr; } -void -VRSystemManagerPuppet::NotifyVSync() -{ - VRSystemManager::NotifyVSync(); - - for (const auto& display: mPuppetHMDs) { - display->Refresh(); - } -} - -uint32_t -VRSystemManagerPuppet::CreateTestDisplay() -{ - if (mPuppetDisplayCount >= kMaxPuppetDisplays) { - MOZ_ASSERT(false); - return mPuppetDisplayCount; - } - return mPuppetDisplayCount++; -} - -void -VRSystemManagerPuppet::ClearTestDisplays() -{ - mPuppetDisplayCount = 0; -} - -void -VRSystemManagerPuppet::Enumerate() -{ - while (mPuppetHMDs.Length() < mPuppetDisplayCount) { - VRDisplayPuppet* puppetDisplay = new VRDisplayPuppet(); - uint32_t deviceID = mPuppetHMDs.Length(); - puppetDisplay->SetDisplayInfo(mPuppetDisplayInfo[deviceID]); - puppetDisplay->SetSensorState(mPuppetDisplaySensorState[deviceID]); - mPuppetHMDs.AppendElement(puppetDisplay); - } - while (mPuppetHMDs.Length() > mPuppetDisplayCount) { - mPuppetHMDs.RemoveElementAt(mPuppetHMDs.Length() - 1); - } -} - -void -VRSystemManagerPuppet::SetPuppetDisplayInfo(const uint32_t& aDeviceID, - const VRDisplayInfo& aDisplayInfo) -{ - if (aDeviceID >= mPuppetDisplayCount) { - MOZ_ASSERT(false); - return; - } - /** - * Even if mPuppetHMDs.Length() <= aDeviceID, we need to - * update mPuppetDisplayInfo[aDeviceID]. In the case that - * a puppet display is added and SetPuppetDisplayInfo is - * immediately called, mPuppetHMDs may not be populated yet. - * VRSystemManagerPuppet::Enumerate() will initialize - * the VRDisplayPuppet later using mPuppetDisplayInfo. - */ - mPuppetDisplayInfo[aDeviceID] = aDisplayInfo; - if (mPuppetHMDs.Length() > aDeviceID) { - /** - * In the event that the VRDisplayPuppet has already been - * created, we update it directly. - */ - mPuppetHMDs[aDeviceID]->SetDisplayInfo(aDisplayInfo); - } -} - -void -VRSystemManagerPuppet::SetPuppetDisplaySensorState(const uint32_t& aDeviceID, - const VRHMDSensorState& aSensorState) -{ - if (aDeviceID >= mPuppetDisplayCount) { - MOZ_ASSERT(false); - return; - } - /** - * Even if mPuppetHMDs.Length() <= aDeviceID, we need to - * update mPuppetDisplaySensorState[aDeviceID]. In the case that - * a puppet display is added and SetPuppetDisplaySensorState is - * immediately called, mPuppetHMDs may not be populated yet. - * VRSystemManagerPuppet::Enumerate() will initialize - * the VRDisplayPuppet later using mPuppetDisplaySensorState. - */ - mPuppetDisplaySensorState[aDeviceID] = aSensorState; - if (mPuppetHMDs.Length() > aDeviceID) { - /** - * In the event that the VRDisplayPuppet has already been - * created, we update it directly. - */ - mPuppetHMDs[aDeviceID]->SetSensorState(aSensorState); - } -} - -void +bool VRSystemManagerPuppet::GetHMDs(nsTArray>& aHMDResult) { - for (auto display: mPuppetHMDs) { - aHMDResult.AppendElement(display); + if (mPuppetHMD == nullptr) { + mPuppetHMD = new VRDisplayPuppet(); } + aHMDResult.AppendElement(mPuppetHMD); + return true; } bool VRSystemManagerPuppet::GetIsPresenting() { - for (const auto& display: mPuppetHMDs) { - const VRDisplayInfo& displayInfo(display->GetDisplayInfo()); - if (displayInfo.GetPresentingGroups() != kVRGroupNone) { - return true; - } + if (mPuppetHMD) { + VRDisplayInfo displayInfo(mPuppetHMD->GetDisplayInfo()); + return displayInfo.GetPresentingGroups() != kVRGroupNone; } + return false; } @@ -915,27 +822,28 @@ VRSystemManagerPuppet::GetControllers(nsTArray>& aContr void VRSystemManagerPuppet::ScanForControllers() { - // We make sure VRSystemManagerPuppet has two controllers - // for each display - const uint32_t newControllerCount = mPuppetHMDs.Length() * 2; + // mPuppetHMD is available after VRDisplay is created + // at GetHMDs(). + if (!mPuppetHMD) { + return; + } + // We make VRSystemManagerPuppet has two controllers always. + const uint32_t newControllerCount = 2; if (newControllerCount != mControllerCount) { RemoveControllers(); // Re-adding controllers to VRControllerManager. - for (const auto& display: mPuppetHMDs) { - uint32_t displayID = display->GetDisplayInfo().GetDisplayID(); - for (uint32_t i = 0; i < 2; i++) { - dom::GamepadHand hand = (i % 2) ? dom::GamepadHand::Right : - dom::GamepadHand::Left; - RefPtr puppetController; - puppetController = new VRControllerPuppet(hand, displayID); - mPuppetController.AppendElement(puppetController); + for (uint32_t i = 0; i < newControllerCount; ++i) { + dom::GamepadHand hand = (i % 2) ? dom::GamepadHand::Right : + dom::GamepadHand::Left; + RefPtr puppetController = new VRControllerPuppet(hand, + mPuppetHMD->GetDisplayInfo().GetDisplayID()); + mPuppetController.AppendElement(puppetController); - // Not already present, add it. - AddGamepad(puppetController->GetControllerInfo()); - ++mControllerCount; - } + // Not already present, add it. + AddGamepad(puppetController->GetControllerInfo()); + ++mControllerCount; } } } diff --git a/gfx/vr/gfxVRPuppet.h b/gfx/vr/gfxVRPuppet.h index e2da9950bcae..39b4cdc4c610 100644 --- a/gfx/vr/gfxVRPuppet.h +++ b/gfx/vr/gfxVRPuppet.h @@ -9,7 +9,6 @@ #include "nsTArray.h" #include "mozilla/RefPtr.h" -#include "nsRefPtrHashtable.h" #include "gfxVR.h" #include "VRDisplayHost.h" @@ -25,6 +24,7 @@ class VRDisplayPuppet : public VRDisplayHost { public: void SetDisplayInfo(const VRDisplayInfo& aDisplayInfo); + virtual void NotifyVSync() override; void SetSensorState(const VRHMDSensorState& aSensorState); void ZeroSensor() override; @@ -50,7 +50,6 @@ protected: public: explicit VRDisplayPuppet(); - void Refresh(); protected: virtual ~VRDisplayPuppet(); @@ -108,17 +107,10 @@ class VRSystemManagerPuppet : public VRSystemManager { public: static already_AddRefed Create(); - uint32_t CreateTestDisplay(); - void ClearTestDisplays(); - void SetPuppetDisplayInfo(const uint32_t& aDeviceID, - const VRDisplayInfo& aDisplayInfo); - void SetPuppetDisplaySensorState(const uint32_t& aDeviceID, - const VRHMDSensorState& aSensorState); virtual void Destroy() override; virtual void Shutdown() override; - virtual void Enumerate() override; - virtual void GetHMDs(nsTArray>& aHMDResult) override; + virtual bool GetHMDs(nsTArray>& aHMDResult) override; virtual bool GetIsPresenting() override; virtual void HandleInput() override; virtual void GetControllers(nsTArray>& @@ -131,7 +123,6 @@ public: double aDuration, uint32_t aPromiseID) override; virtual void StopVibrateHaptic(uint32_t aControllerIdx) override; - virtual void NotifyVSync() override; protected: VRSystemManagerPuppet(); @@ -148,15 +139,9 @@ private: const dom::GamepadPoseState& aPose, VRControllerHost* aController); - // Enumerated puppet hardware devices, as seen by Web APIs: - nsTArray> mPuppetHMDs; + // there can only be one + RefPtr mPuppetHMD; nsTArray> mPuppetController; - - // Emulated hardware state, persistent through VRSystemManager::Shutdown(): - static const uint32_t kMaxPuppetDisplays = 5; - uint32_t mPuppetDisplayCount; - VRDisplayInfo mPuppetDisplayInfo[kMaxPuppetDisplays]; - VRHMDSensorState mPuppetDisplaySensorState[kMaxPuppetDisplays]; }; } // namespace gfx diff --git a/gfx/vr/ipc/VRManagerChild.cpp b/gfx/vr/ipc/VRManagerChild.cpp index f6b549a5a71c..78dc67e478ea 100644 --- a/gfx/vr/ipc/VRManagerChild.cpp +++ b/gfx/vr/ipc/VRManagerChild.cpp @@ -405,14 +405,7 @@ VRManagerChild::RecvReplyCreateVRServiceTestController(const nsCString& aID, MOZ_CRASH("We should always have a promise."); } - if (aDeviceID == 0) { - // A value of 0 indicates that the controller could not - // be created. Most likely due to having no VR display - // to associate it with. - p->MaybeRejectWithUndefined(); - } else { - p->MaybeResolve(new VRMockController(aID, aDeviceID)); - } + p->MaybeResolve(new VRMockController(aID, aDeviceID)); mPromiseList.Remove(aPromiseID); return IPC_OK(); } diff --git a/gfx/vr/ipc/VRManagerParent.cpp b/gfx/vr/ipc/VRManagerParent.cpp index ec7e65de3d3c..c270299cce96 100644 --- a/gfx/vr/ipc/VRManagerParent.cpp +++ b/gfx/vr/ipc/VRManagerParent.cpp @@ -20,7 +20,8 @@ using namespace layers; namespace gfx { VRManagerParent::VRManagerParent(ProcessId aChildProcessId, bool aIsContentChild) - : mControllerTestID(1) + : mDisplayTestID(0) + , mControllerTestID(0) , mHaveEventListener(false) , mHaveControllerListener(false) , mIsContentChild(aIsContentChild) @@ -246,19 +247,37 @@ VRManagerParent::RecvCreateVRTestSystem() { VRManager* vm = VRManager::Get(); vm->CreateVRTestSystem(); - // The mControllerTestID is 1 based - mControllerTestID = 1; + mDisplayTestID = 0; + mControllerTestID = 0; return IPC_OK(); } mozilla::ipc::IPCResult VRManagerParent::RecvCreateVRServiceTestDisplay(const nsCString& aID, const uint32_t& aPromiseID) { + nsTArray displayInfoArray; + impl::VRDisplayPuppet* displayPuppet = nullptr; VRManager* vm = VRManager::Get(); - VRSystemManagerPuppet* puppetManager = vm->GetPuppetManager(); - uint32_t deviceID = puppetManager->CreateTestDisplay(); + vm->RefreshVRDisplays(); - if (SendReplyCreateVRServiceTestDisplay(aID, aPromiseID, deviceID)) { + // Get VRDisplayPuppet from VRManager + vm->GetVRDisplayInfo(displayInfoArray); + for (auto& displayInfo : displayInfoArray) { + if (displayInfo.GetType() == VRDeviceType::Puppet) { + displayPuppet = static_cast( + vm->GetDisplay(displayInfo.GetDisplayID()).get()); + break; + } + } + + MOZ_ASSERT(displayPuppet); + MOZ_ASSERT(!mDisplayTestID); // We have only one display in VRSystemManagerPuppet. + + if (!mVRDisplayTests.Get(mDisplayTestID, nullptr)) { + mVRDisplayTests.Put(mDisplayTestID, displayPuppet); + } + + if (SendReplyCreateVRServiceTestDisplay(aID, aPromiseID, mDisplayTestID)) { return IPC_OK(); } @@ -268,20 +287,14 @@ VRManagerParent::RecvCreateVRServiceTestDisplay(const nsCString& aID, const uint mozilla::ipc::IPCResult VRManagerParent::RecvCreateVRServiceTestController(const nsCString& aID, const uint32_t& aPromiseID) { - uint32_t controllerIdx = 1; // ID's are 1 based + uint32_t controllerIdx = 0; nsTArray controllerInfoArray; impl::VRControllerPuppet* controllerPuppet = nullptr; VRManager* vm = VRManager::Get(); - /** - * When running headless mochitests on some of our automated test - * infrastructure, 2d display vsyncs are not always generated. - * In this case, the test controllers can't be created immediately - * after the VR display was created as the state of the VR displays - * are updated during vsync. - * To workaround, we produce a vsync manually. - */ - vm->NotifyVsync(TimeStamp::Now()); + if (mHaveControllerListener) { + vm->RefreshVRControllers(); + } // Get VRControllerPuppet from VRManager vm->GetVRControllerInfo(controllerInfoArray); @@ -296,22 +309,16 @@ VRManagerParent::RecvCreateVRServiceTestController(const nsCString& aID, const u } } - // We might not have a controllerPuppet if the test did - // not create a VR display first. - if (!controllerPuppet) { - // We send a device ID of "0" to indicate failure - if (SendReplyCreateVRServiceTestController(aID, aPromiseID, 0)) { - return IPC_OK(); - } - } else { - if (!mVRControllerTests.Get(mControllerTestID, nullptr)) { - mVRControllerTests.Put(mControllerTestID, controllerPuppet); - } + MOZ_ASSERT(controllerPuppet); + MOZ_ASSERT(mControllerTestID < 2); // We have only two controllers in VRSystemManagerPuppet. - if (SendReplyCreateVRServiceTestController(aID, aPromiseID, mControllerTestID)) { - ++mControllerTestID; - return IPC_OK(); - } + if (!mVRControllerTests.Get(mControllerTestID, nullptr)) { + mVRControllerTests.Put(mControllerTestID, controllerPuppet); + } + + if (SendReplyCreateVRServiceTestController(aID, aPromiseID, mControllerTestID)) { + ++mControllerTestID; + return IPC_OK(); } return IPC_FAIL(this, "SendReplyCreateVRServiceTestController fail"); @@ -321,9 +328,11 @@ mozilla::ipc::IPCResult VRManagerParent::RecvSetDisplayInfoToMockDisplay(const uint32_t& aDeviceID, const VRDisplayInfo& aDisplayInfo) { - VRManager* vm = VRManager::Get(); - VRSystemManagerPuppet* puppetManager = vm->GetPuppetManager(); - puppetManager->SetPuppetDisplayInfo(aDeviceID, aDisplayInfo); + RefPtr displayPuppet; + mVRDisplayTests.Get(aDeviceID, + getter_AddRefs(displayPuppet)); + MOZ_ASSERT(displayPuppet); + displayPuppet->SetDisplayInfo(aDisplayInfo); return IPC_OK(); } @@ -331,33 +340,23 @@ mozilla::ipc::IPCResult VRManagerParent::RecvSetSensorStateToMockDisplay(const uint32_t& aDeviceID, const VRHMDSensorState& aSensorState) { - VRManager* vm = VRManager::Get(); - VRSystemManagerPuppet* puppetManager = vm->GetPuppetManager(); - puppetManager->SetPuppetDisplaySensorState(aDeviceID, aSensorState); + RefPtr displayPuppet; + mVRDisplayTests.Get(aDeviceID, + getter_AddRefs(displayPuppet)); + MOZ_ASSERT(displayPuppet); + displayPuppet->SetSensorState(aSensorState); return IPC_OK(); } -already_AddRefed -VRManagerParent::GetControllerPuppet(uint32_t aDeviceID) -{ - // aDeviceID for controllers start at 1 and are - // used as a key to mVRControllerTests - MOZ_ASSERT(aDeviceID > 0); - RefPtr controllerPuppet; - mVRControllerTests.Get(aDeviceID, - getter_AddRefs(controllerPuppet)); - MOZ_ASSERT(controllerPuppet); - return controllerPuppet.forget(); -} - mozilla::ipc::IPCResult VRManagerParent::RecvNewButtonEventToMockController(const uint32_t& aDeviceID, const long& aButton, const bool& aPressed) { - RefPtr controllerPuppet = GetControllerPuppet(aDeviceID); - if (controllerPuppet) { - controllerPuppet->SetButtonPressState(aButton, aPressed); - } + RefPtr controllerPuppet; + mVRControllerTests.Get(aDeviceID, + getter_AddRefs(controllerPuppet)); + MOZ_ASSERT(controllerPuppet); + controllerPuppet->SetButtonPressState(aButton, aPressed); return IPC_OK(); } @@ -365,10 +364,11 @@ mozilla::ipc::IPCResult VRManagerParent::RecvNewAxisMoveEventToMockController(const uint32_t& aDeviceID, const long& aAxis, const double& aValue) { - RefPtr controllerPuppet = GetControllerPuppet(aDeviceID); - if (controllerPuppet) { - controllerPuppet->SetAxisMoveState(aAxis, aValue); - } + RefPtr controllerPuppet; + mVRControllerTests.Get(aDeviceID, + getter_AddRefs(controllerPuppet)); + MOZ_ASSERT(controllerPuppet); + controllerPuppet->SetAxisMoveState(aAxis, aValue); return IPC_OK(); } @@ -376,10 +376,11 @@ mozilla::ipc::IPCResult VRManagerParent::RecvNewPoseMoveToMockController(const uint32_t& aDeviceID, const GamepadPoseState& pose) { - RefPtr controllerPuppet = GetControllerPuppet(aDeviceID); - if (controllerPuppet) { - controllerPuppet->SetPoseMoveState(pose); - } + RefPtr controllerPuppet; + mVRControllerTests.Get(aDeviceID, + getter_AddRefs(controllerPuppet)); + MOZ_ASSERT(controllerPuppet); + controllerPuppet->SetPoseMoveState(pose); return IPC_OK(); } diff --git a/gfx/vr/ipc/VRManagerParent.h b/gfx/vr/ipc/VRManagerParent.h index c5606371a55d..9129a3bbbef0 100644 --- a/gfx/vr/ipc/VRManagerParent.h +++ b/gfx/vr/ipc/VRManagerParent.h @@ -83,7 +83,6 @@ private: static void RegisterVRManagerInVRListenerThread(VRManagerParent* aVRManager); void DeferredDestroy(); - already_AddRefed GetControllerPuppet(uint32_t aDeviceID); // This keeps us alive until ActorDestroy(), at which point we do a // deferred destruction of ourselves. @@ -92,7 +91,9 @@ private: // Keep the VRManager alive, until we have destroyed ourselves. RefPtr mVRManagerHolder; + nsRefPtrHashtable mVRDisplayTests; nsRefPtrHashtable mVRControllerTests; + uint32_t mDisplayTestID; uint32_t mControllerTestID; bool mHaveEventListener; bool mHaveControllerListener; diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 90ee3f9065ff..b86f4dfba2a1 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -5157,20 +5157,6 @@ pref("dom.vr.openvr.enabled", true); // See Bug 1310663 (Linux) pref("dom.vr.openvr.enabled", false); #endif -// Minimum number of milliseconds that the browser will wait before -// attempting to poll again for connected VR controllers. The browser -// will not attempt to poll for VR controllers until it needs to use them. -pref("dom.vr.controller.enumerate.interval", 1000); -// Minimum number of milliseconds that the browser will wait before -// attempting to poll again for connected VR displays. The browser -// will not attempt to poll for VR displays until it needs to use -// them, such as when detecting a WebVR site. -pref("dom.vr.display.enumerate.interval", 5000); -// Minimum number of milliseconds that the VR session will be kept -// alive after the browser and content no longer are using the -// hardware. If a VR multitasking environment, this should be set -// very low or set to 0. -pref("dom.vr.inactive.timeout", 5000); // Pose prediction reduces latency effects by returning future predicted HMD // poses to callers of the WebVR API. This currently only has an effect for // Oculus Rift on SDK 0.8 or greater.