Bug 1287944 - Improve interaction with Oculus Home r=daoshengmu

- Now destroying and re-creating Oculus sessions when switching
  between magic window and immersive WebVR (BeginPresent / ExitPresent)
- Now sending flags to Oculus ovr_initilize to specify if Firefox will
  be presenting to the VR display or just using tracking
- Now coordinating oculus session shutdown and restart between the
  VR controllers and the VR display with reference counting.
- Now able to return to Oculus home after using WebVR
- Magic window / non-exclusive sessions no longer take over the VR headset
  causing it to display a message that Firefox.exe is not responding.


MozReview-Commit-ID: EnRsxt6ZSzg

--HG--
extra : rebase_source : d1ecf52e064ffe88c2cdebb011b8ffa9beb7b46e
This commit is contained in:
Kearwood "Kip" Gilbert 2017-07-04 13:28:27 -07:00
parent 90de18de8a
commit d4f04befed
14 changed files with 642 additions and 322 deletions

View File

@ -355,6 +355,8 @@ private:
DECL_GFX_PREF(Live, "dom.vr.controller_trigger_threshold", VRControllerTriggerThreshold, float, 0.1f);
DECL_GFX_PREF(Live, "dom.vr.navigation.timeout", VRNavigationTimeout, int32_t, 1000);
DECL_GFX_PREF(Once, "dom.vr.oculus.enabled", VROculusEnabled, bool, true);
DECL_GFX_PREF(Live, "dom.vr.oculus.present.timeout", VROculusPresentTimeout, int32_t, 10000);
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.poseprediction.enabled", VRPosePredictionEnabled, bool, true);

View File

@ -264,20 +264,26 @@ VRManager::RefreshVRDisplays(bool aMustDispatch)
* in the future.
*/
for (uint32_t i = 0; i < mManagers.Length() && displays.Length() == 0; ++i) {
mManagers[i]->GetHMDs(displays);
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;
bool displaySetChanged = false;
if (displays.Length() != mVRDisplays.Count()) {
// Catch cases where a VR display has been removed
displayInfoChanged = true;
displaySetChanged = true;
}
for (const auto& display: displays) {
if (!GetDisplay(display->GetDisplayInfo().GetDisplayID())) {
// This is a new display
displayInfoChanged = true;
displaySetChanged = true;
break;
}
@ -288,14 +294,15 @@ VRManager::RefreshVRDisplays(bool aMustDispatch)
}
}
if (displayInfoChanged) {
// Rebuild the HashMap if there are additions or removals
if (displaySetChanged) {
mVRDisplays.Clear();
for (const auto& display: displays) {
mVRDisplays.Put(display->GetDisplayInfo().GetDisplayID(), display);
}
}
if (displayInfoChanged || aMustDispatch) {
if (displayInfoChanged || displaySetChanged || aMustDispatch) {
DispatchVRDisplayInfoUpdate();
}
}

View File

@ -320,7 +320,7 @@ public:
virtual void Destroy() = 0;
virtual void Shutdown() = 0;
virtual void GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult) = 0;
virtual bool GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult) = 0;
virtual bool GetIsPresenting() = 0;
virtual void HandleInput() = 0;
virtual void GetControllers(nsTArray<RefPtr<VRControllerHost>>& aControllerResult) = 0;

View File

@ -514,21 +514,23 @@ VRSystemManagerOSVR::Shutdown()
osvr_ClientShutdown(m_ctx);
}
void
bool
VRSystemManagerOSVR::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
{
// make sure context, interface and display are initialized
CheckOSVRStatus();
if (!Init()) {
return;
return false;
}
mHMDInfo = new VRDisplayOSVR(&m_ctx, &m_iface, &m_display);
if (mHMDInfo) {
aHMDResult.AppendElement(mHMDInfo);
return true;
}
return false;
}
bool

View File

@ -65,7 +65,7 @@ public:
static already_AddRefed<VRSystemManagerOSVR> Create();
virtual void Destroy() override;
virtual void Shutdown() override;
virtual void GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult) override;
virtual bool GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult) override;
virtual bool GetIsPresenting() override;
virtual void HandleInput() override;
virtual void GetControllers(nsTArray<RefPtr<VRControllerHost>>&

File diff suppressed because it is too large Load Diff

View File

@ -7,6 +7,7 @@
#define GFX_VR_OCULUS_H
#include "nsTArray.h"
#include "nsISupportsImpl.h" // For NS_INLINE_DECL_REFCOUNTING
#include "mozilla/RefPtr.h"
#include "mozilla/gfx/2D.h"
@ -33,6 +34,49 @@ enum class OculusControllerAxisType : uint16_t {
NumVRControllerAxisType
};
class VROculusSession
{
NS_INLINE_DECL_REFCOUNTING(VROculusSession);
public:
VROculusSession();
void Refresh();
bool IsTrackingReady() const;
bool IsRenderReady() const;
ovrSession Get();
void StartPresentation(const IntSize& aSize);
void StopPresentation();
void StopTracking();
bool IsQuitTimeoutActive();
already_AddRefed<layers::CompositingRenderTargetD3D11> GetNextRenderTarget();
ovrTextureSwapChain GetSwapChain();
private:
PRLibrary* mOvrLib;
ovrSession mSession;
ovrInitFlags mInitFlags;
ovrTextureSwapChain mTextureSet;
nsTArray<RefPtr<layers::CompositingRenderTargetD3D11>> mRenderTargets;
bool mPresenting;
IntSize mPresentationSize;
RefPtr<ID3D11Device> mDevice;
// The timestamp of the last time Oculus set ShouldQuit to true.
TimeStamp mLastShouldQuit;
// The timestamp of the last ending presentation
TimeStamp mLastPresentationEnd;
~VROculusSession();
void Uninitialize(bool aUnloadLib);
bool Initialize(ovrInitFlags aFlags);
bool LoadOvrLib();
void UnloadOvrLib();
bool StartSession();
void StopSession();
bool StartLib(ovrInitFlags aFlags);
void StopLib();
bool StartRendering();
void StopRendering();
};
class VRDisplayOculus : public VRDisplayHost
{
public:
@ -50,24 +94,17 @@ protected:
void UpdateStageParameters();
public:
explicit VRDisplayOculus(ovrSession aSession);
explicit VRDisplayOculus(VROculusSession* aSession);
void Destroy();
protected:
virtual ~VRDisplayOculus();
void Destroy();
bool RequireSession();
const ovrHmdDesc& GetHmdDesc();
already_AddRefed<layers::CompositingRenderTargetD3D11> GetNextRenderTarget();
VRHMDSensorState GetSensorState(double absTime);
ovrHmdDesc mDesc;
ovrSession mSession;
RefPtr<VROculusSession> mSession;
ovrFovPort mFOVPort[2];
ovrTextureSwapChain mTextureSet;
nsTArray<RefPtr<layers::CompositingRenderTargetD3D11>> mRenderTargets;
RefPtr<ID3D11Device> mDevice;
RefPtr<ID3D11DeviceContext> mContext;
@ -81,7 +118,6 @@ protected:
RefPtr<ID3D11Buffer> mVertexBuffer;
RefPtr<ID3D11InputLayout> mInputLayout;
bool mIsPresenting;
float mEyeHeight;
bool UpdateConstantBuffers();
@ -137,7 +173,7 @@ public:
static already_AddRefed<VRSystemManagerOculus> Create();
virtual void Destroy() override;
virtual void Shutdown() override;
virtual void GetHMDs(nsTArray<RefPtr<VRDisplayHost> >& aHMDResult) override;
virtual bool GetHMDs(nsTArray<RefPtr<VRDisplayHost> >& aHMDResult) override;
virtual bool GetIsPresenting() override;
virtual void HandleInput() override;
virtual void GetControllers(nsTArray<RefPtr<VRControllerHost>>&
@ -149,13 +185,7 @@ public:
virtual void StopVibrateHaptic(uint32_t aControllerIdx) override;
protected:
VRSystemManagerOculus()
: mOvrLib(nullptr), mSession(nullptr), mStarted(false)
{}
bool Startup();
bool LoadOvrLib();
void UnloadOvrLib();
VRSystemManagerOculus();
private:
void HandleButtonPress(uint32_t aControllerIdx,
@ -172,12 +202,9 @@ private:
void HandleHandTriggerPress(uint32_t aControllerIdx, uint32_t aButton, float aValue);
void HandleTouchEvent(uint32_t aControllerIdx, uint32_t aButton,
uint64_t aTouchMask, uint64_t aTouched);
PRLibrary* mOvrLib;
RefPtr<impl::VRDisplayOculus> mHMDInfo;
RefPtr<impl::VRDisplayOculus> mDisplay;
nsTArray<RefPtr<impl::VRControllerOculus>> mOculusController;
RefPtr<nsIThread> mOculusThread;
ovrSession mSession;
bool mStarted;
RefPtr<impl::VROculusSession> mSession;
};
} // namespace gfx

View File

@ -549,7 +549,7 @@ VRSystemManagerOpenVR::Shutdown()
mVRSystem = nullptr;
}
void
bool
VRSystemManagerOpenVR::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
{
if (!::vr::VR_IsHmdPresent() ||
@ -563,23 +563,23 @@ VRSystemManagerOpenVR::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
::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;
@ -588,7 +588,9 @@ VRSystemManagerOpenVR::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
if (mOpenVRHMD) {
aHMDResult.AppendElement(mOpenVRHMD);
return true;
}
return false;
}
bool

View File

@ -108,7 +108,7 @@ public:
virtual void Destroy() override;
virtual void Shutdown() override;
virtual void GetHMDs(nsTArray<RefPtr<VRDisplayHost> >& aHMDResult) override;
virtual bool GetHMDs(nsTArray<RefPtr<VRDisplayHost> >& aHMDResult) override;
virtual bool GetIsPresenting() override;
virtual void HandleInput() override;
virtual void GetControllers(nsTArray<RefPtr<VRControllerHost>>&

View File

@ -622,13 +622,14 @@ VRSystemManagerPuppet::Shutdown()
mPuppetHMD = nullptr;
}
void
bool
VRSystemManagerPuppet::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
{
if (mPuppetHMD == nullptr) {
mPuppetHMD = new VRDisplayPuppet();
}
aHMDResult.AppendElement(mPuppetHMD);
return true;
}
bool

View File

@ -103,7 +103,7 @@ public:
virtual void Destroy() override;
virtual void Shutdown() override;
virtual void GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult) override;
virtual bool GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult) override;
virtual bool GetIsPresenting() override;
virtual void HandleInput() override;
virtual void GetControllers(nsTArray<RefPtr<VRControllerHost>>&

View File

@ -40,6 +40,17 @@ VRLayerParent::ActorDestroy(ActorDestroyReason aWhy)
void
VRLayerParent::Destroy()
{
if (mVRDisplayID) {
VRManager* vm = VRManager::Get();
RefPtr<gfx::VRDisplayHost> display = vm->GetDisplay(mVRDisplayID);
if (display) {
display->RemoveLayer(this);
}
// 0 will never be a valid VRDisplayID; we can use it to indicate that
// we are destroyed and no longer associated with a display.
mVRDisplayID = 0;
}
if (mIPCOpen) {
Unused << PVRLayerParent::Send__delete__(this);
}
@ -48,8 +59,10 @@ VRLayerParent::Destroy()
mozilla::ipc::IPCResult
VRLayerParent::RecvSubmitFrame(PTextureParent* texture)
{
VRManager* vm = VRManager::Get();
vm->SubmitFrame(this, texture, mLeftEyeRect, mRightEyeRect);
if (mVRDisplayID) {
VRManager* vm = VRManager::Get();
vm->SubmitFrame(this, texture, mLeftEyeRect, mRightEyeRect);
}
return IPC_OK();
}

View File

@ -84,14 +84,6 @@ VRManagerParent::AllocPVRLayerParent(const uint32_t& aDisplayID,
bool
VRManagerParent::DeallocPVRLayerParent(PVRLayerParent* actor)
{
gfx::VRLayerParent* layer = static_cast<gfx::VRLayerParent*>(actor);
VRManager* vm = VRManager::Get();
RefPtr<gfx::VRDisplayHost> display = vm->GetDisplay(layer->GetDisplayID());
if (display) {
display->RemoveLayer(layer);
}
delete actor;
return true;
}

View File

@ -5155,6 +5155,22 @@ pref("dom.vr.controller_trigger_threshold", "0.1");
pref("dom.vr.navigation.timeout", 5000);
// Oculus device
pref("dom.vr.oculus.enabled", true);
// Minimum number of milliseconds after content has stopped VR presentation
// before the Oculus session is re-initialized to an invisible / tracking
// only mode. If this value is too high, users will need to wait longer
// after stopping WebVR presentation before automatically returning to the
// Oculus home interface. (They can immediately return to the Oculus Home
// interface through the Oculus HUD without waiting this duration)
// If this value is too low, the Oculus Home interface may be visible
// momentarily during VR link navigation.
pref("dom.vr.oculus.present.timeout", 10000);
// Minimum number of milliseconds that the browser will wait before
// reloading the Oculus OVR library after seeing a "ShouldQuit" flag set.
// Oculus requests that we shut down and unload the OVR library, by setting
// a "ShouldQuit" flag. To ensure that we don't interfere with
// Oculus software auto-updates, we will not attempt to re-load the
// OVR library until this timeout has elapsed.
pref("dom.vr.oculus.quit.timeout", 30000);
// OSVR device
pref("dom.vr.osvr.enabled", false);
// OpenVR device