From 89b524f028f2f1c66973a8ee1c8b23900d3c5ee0 Mon Sep 17 00:00:00 2001 From: "Kearwood \"Kip\" Gilbert" Date: Tue, 8 May 2018 11:31:28 -0700 Subject: [PATCH] Bug 1469967 - Implement immersive mode for gfxVRExternal r=rbarker - The VR External interface/shmem and gfxVRExternal are updated to enable entering VR, exiting VR, and submitting frames. - You can now construct gfxVRExternal using a pointer to the VR External API shmem, if it is created elsewhere. MozReview-Commit-ID: LZuoLvoEmKO --HG-- extra : rebase_source : ab38ae4c34f9ac5cdd69e7222f12b1c758307057 --- gfx/vr/VRDisplayHost.cpp | 91 ++---------- gfx/vr/VRDisplayHost.h | 22 +-- gfx/vr/VRDisplayLocal.cpp | 132 +++++++++++++++++ gfx/vr/VRDisplayLocal.h | 61 ++++++++ gfx/vr/VRManager.cpp | 6 + gfx/vr/external_api/moz_external_vr.h | 9 +- gfx/vr/gfxVRExternal.cpp | 198 +++++++++++++++++++------- gfx/vr/gfxVRExternal.h | 39 +++-- gfx/vr/gfxVROSVR.cpp | 4 +- gfx/vr/gfxVROSVR.h | 6 +- gfx/vr/gfxVROculus.cpp | 6 +- gfx/vr/gfxVROculus.h | 4 +- gfx/vr/gfxVROpenVR.cpp | 28 ++-- gfx/vr/gfxVROpenVR.h | 14 +- gfx/vr/gfxVRPuppet.cpp | 6 +- gfx/vr/gfxVRPuppet.h | 4 +- gfx/vr/ipc/VRMessageUtils.h | 2 + gfx/vr/moz.build | 1 + 18 files changed, 422 insertions(+), 211 deletions(-) create mode 100644 gfx/vr/VRDisplayLocal.cpp create mode 100644 gfx/vr/VRDisplayLocal.h diff --git a/gfx/vr/VRDisplayHost.cpp b/gfx/vr/VRDisplayHost.cpp index 98df3fbf4fd0..af9a37a76421 100644 --- a/gfx/vr/VRDisplayHost.cpp +++ b/gfx/vr/VRDisplayHost.cpp @@ -273,83 +273,8 @@ VRDisplayHost::SubmitFrameInternal(const layers::SurfaceDescriptor &aTexture, #endif // !defined(MOZ_WIDGET_ANDROID) AUTO_PROFILER_TRACING("VR", "SubmitFrameAtVRDisplayHost"); - mFrameStarted = false; - switch (aTexture.type()) { - -#if defined(XP_WIN) - case SurfaceDescriptor::TSurfaceDescriptorD3D10: { - if (!CreateD3DObjects()) { - return; - } - const SurfaceDescriptorD3D10& surf = aTexture.get_SurfaceDescriptorD3D10(); - RefPtr dxTexture; - HRESULT hr = mDevice->OpenSharedResource((HANDLE)surf.handle(), - __uuidof(ID3D11Texture2D), - (void**)(ID3D11Texture2D**)getter_AddRefs(dxTexture)); - if (FAILED(hr) || !dxTexture) { - NS_WARNING("Failed to open shared texture"); - return; - } - - // Similar to LockD3DTexture in TextureD3D11.cpp - RefPtr mutex; - dxTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex)); - if (mutex) { - HRESULT hr = mutex->AcquireSync(0, 1000); - if (hr == WAIT_TIMEOUT) { - gfxDevCrash(LogReason::D3DLockTimeout) << "D3D lock mutex timeout"; - } - else if (hr == WAIT_ABANDONED) { - gfxCriticalNote << "GFX: D3D11 lock mutex abandoned"; - } - if (FAILED(hr)) { - NS_WARNING("Failed to lock the texture"); - return; - } - } - bool success = SubmitFrame(dxTexture, surf.size(), - aLeftEyeRect, aRightEyeRect); - if (mutex) { - HRESULT hr = mutex->ReleaseSync(0); - if (FAILED(hr)) { - NS_WARNING("Failed to unlock the texture"); - } - } - if (!success) { - return; - } - break; - } -#elif defined(XP_MACOSX) - case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface: { - const auto& desc = aTexture.get_SurfaceDescriptorMacIOSurface(); - RefPtr surf = MacIOSurface::LookupSurface(desc.surfaceId(), - desc.scaleFactor(), - !desc.isOpaque()); - if (!surf) { - NS_WARNING("VRDisplayHost::SubmitFrame failed to get a MacIOSurface"); - return; - } - IntSize texSize = gfx::IntSize(surf->GetDevicePixelWidth(), - surf->GetDevicePixelHeight()); - if (!SubmitFrame(surf, texSize, aLeftEyeRect, aRightEyeRect)) { - return; - } - break; - } -#elif defined(MOZ_WIDGET_ANDROID) - case SurfaceDescriptor::TSurfaceTextureDescriptor: { - const SurfaceTextureDescriptor& desc = aTexture.get_SurfaceTextureDescriptor(); - if (!SubmitFrame(desc, aLeftEyeRect, aRightEyeRect)) { - return; - } - break; - } -#endif - default: { - NS_WARNING("Unsupported SurfaceDescriptor type for VR layer texture"); - return; - } + if (!SubmitFrame(aTexture, aFrameId, aLeftEyeRect, aRightEyeRect)) { + return; } #if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_ANDROID) @@ -381,12 +306,6 @@ VRDisplayHost::SubmitFrame(VRLayerParent* aLayer, const gfx::Rect& aLeftEyeRect, const gfx::Rect& aRightEyeRect) { -#if !defined(MOZ_WIDGET_ANDROID) - if (!mSubmitThread) { - mSubmitThread = new VRThread(NS_LITERAL_CSTRING("VR_SubmitFrame")); - } -#endif // !defined(MOZ_WIDGET_ANDROID) - if ((mDisplayInfo.mGroupMask & aLayer->GetGroup()) == 0) { // Suppress layers hidden by the group mask return; @@ -397,12 +316,18 @@ VRDisplayHost::SubmitFrame(VRLayerParent* aLayer, return; } + mFrameStarted = false; + RefPtr submit = NewRunnableMethod, uint64_t, StoreCopyPassByConstLRef, StoreCopyPassByConstLRef>( "gfx::VRDisplayHost::SubmitFrameInternal", this, &VRDisplayHost::SubmitFrameInternal, aTexture, aFrameId, aLeftEyeRect, aRightEyeRect); + #if !defined(MOZ_WIDGET_ANDROID) + if (!mSubmitThread) { + mSubmitThread = new VRThread(NS_LITERAL_CSTRING("VR_SubmitFrame")); + } mSubmitThread->Start(); mSubmitThread->PostTask(submit.forget()); #else diff --git a/gfx/vr/VRDisplayHost.h b/gfx/vr/VRDisplayHost.h index 6b00b489c0a1..91c4de733e83 100644 --- a/gfx/vr/VRDisplayHost.h +++ b/gfx/vr/VRDisplayHost.h @@ -72,25 +72,13 @@ protected: explicit VRDisplayHost(VRDeviceType aType); virtual ~VRDisplayHost(); -#if defined(XP_WIN) - // Subclasses should override this SubmitFrame function. - // Returns true if the SubmitFrame call will block as necessary - // to control timing of the next frame and throttle the render loop - // for the needed framerate. - virtual bool SubmitFrame(ID3D11Texture2D* aSource, - const IntSize& aSize, + // This SubmitFrame() must be overridden by children and block until + // the next frame is ready to start and the resources in aTexture can + // safely be released. + virtual bool SubmitFrame(const layers::SurfaceDescriptor& aTexture, + uint64_t aFrameId, const gfx::Rect& aLeftEyeRect, const gfx::Rect& aRightEyeRect) = 0; -#elif defined(XP_MACOSX) - virtual bool SubmitFrame(MacIOSurface* aMacIOSurface, - const IntSize& aSize, - const gfx::Rect& aLeftEyeRect, - const gfx::Rect& aRightEyeRect) = 0; -#elif defined(MOZ_WIDGET_ANDROID) - virtual bool SubmitFrame(const mozilla::layers::SurfaceTextureDescriptor& aSurface, - const gfx::Rect& aLeftEyeRect, - const gfx::Rect& aRightEyeRect) = 0; -#endif VRDisplayInfo mDisplayInfo; diff --git a/gfx/vr/VRDisplayLocal.cpp b/gfx/vr/VRDisplayLocal.cpp new file mode 100644 index 000000000000..7bf191696e28 --- /dev/null +++ b/gfx/vr/VRDisplayLocal.cpp @@ -0,0 +1,132 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 "VRDisplayLocal.h" +#include "gfxPrefs.h" +#include "gfxVR.h" +#include "ipc/VRLayerParent.h" +#include "mozilla/layers/TextureHost.h" +#include "mozilla/dom/GamepadBinding.h" // For GamepadMappingType +#include "VRThread.h" + +#if defined(XP_WIN) + +#include +#include "gfxWindowsPlatform.h" +#include "../layers/d3d11/CompositorD3D11.h" +#include "mozilla/gfx/DeviceManagerDx.h" +#include "mozilla/layers/TextureD3D11.h" + +#elif defined(XP_MACOSX) + +#include "mozilla/gfx/MacIOSurface.h" + +#endif + +#if defined(MOZ_WIDGET_ANDROID) +#include "mozilla/layers/CompositorThread.h" +#endif // defined(MOZ_WIDGET_ANDROID) + +using namespace mozilla; +using namespace mozilla::gfx; +using namespace mozilla::layers; + +VRDisplayLocal::VRDisplayLocal(VRDeviceType aType) + : VRDisplayHost(aType) +{ + MOZ_COUNT_CTOR_INHERITED(VRDisplayLocal, VRDisplayHost); +} + +VRDisplayLocal::~VRDisplayLocal() +{ + MOZ_COUNT_DTOR_INHERITED(VRDisplayLocal, VRDisplayHost); +} + +bool +VRDisplayLocal::SubmitFrame(const layers::SurfaceDescriptor &aTexture, + uint64_t aFrameId, + const gfx::Rect& aLeftEyeRect, + const gfx::Rect& aRightEyeRect) +{ +#if !defined(MOZ_WIDGET_ANDROID) + MOZ_ASSERT(mSubmitThread->GetThread() == NS_GetCurrentThread()); +#endif // !defined(MOZ_WIDGET_ANDROID) + + switch (aTexture.type()) { + +#if defined(XP_WIN) + case SurfaceDescriptor::TSurfaceDescriptorD3D10: { + if (!CreateD3DObjects()) { + return false; + } + const SurfaceDescriptorD3D10& surf = aTexture.get_SurfaceDescriptorD3D10(); + RefPtr dxTexture; + HRESULT hr = mDevice->OpenSharedResource((HANDLE)surf.handle(), + __uuidof(ID3D11Texture2D), + (void**)(ID3D11Texture2D**)getter_AddRefs(dxTexture)); + if (FAILED(hr) || !dxTexture) { + NS_WARNING("Failed to open shared texture"); + return false; + } + + // Similar to LockD3DTexture in TextureD3D11.cpp + RefPtr mutex; + dxTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex)); + if (mutex) { + HRESULT hr = mutex->AcquireSync(0, 1000); + if (hr == WAIT_TIMEOUT) { + gfxDevCrash(LogReason::D3DLockTimeout) << "D3D lock mutex timeout"; + } + else if (hr == WAIT_ABANDONED) { + gfxCriticalNote << "GFX: D3D11 lock mutex abandoned"; + } + if (FAILED(hr)) { + NS_WARNING("Failed to lock the texture"); + return false; + } + } + bool success = SubmitFrame(dxTexture, surf.size(), + aLeftEyeRect, aRightEyeRect); + if (mutex) { + HRESULT hr = mutex->ReleaseSync(0); + if (FAILED(hr)) { + NS_WARNING("Failed to unlock the texture"); + } + } + return success; + } +#elif defined(XP_MACOSX) + case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface: { + const auto& desc = aTexture.get_SurfaceDescriptorMacIOSurface(); + RefPtr surf = MacIOSurface::LookupSurface(desc.surfaceId(), + desc.scaleFactor(), + !desc.isOpaque()); + if (!surf) { + NS_WARNING("VRDisplayHost::SubmitFrame failed to get a MacIOSurface"); + return false; + } + IntSize texSize = gfx::IntSize(surf->GetDevicePixelWidth(), + surf->GetDevicePixelHeight()); + if (!SubmitFrame(surf, texSize, aLeftEyeRect, aRightEyeRect)) { + return false; + } + return true; + } +#elif defined(MOZ_WIDGET_ANDROID) + case SurfaceDescriptor::TSurfaceTextureDescriptor: { + const SurfaceTextureDescriptor& desc = aTexture.get_SurfaceTextureDescriptor(); + if (!SubmitFrame(desc, aLeftEyeRect, aRightEyeRect)) { + return false; + } + return true; + } +#endif + default: { + NS_WARNING("Unsupported SurfaceDescriptor type for VR layer texture"); + return false; + } + } +} diff --git a/gfx/vr/VRDisplayLocal.h b/gfx/vr/VRDisplayLocal.h new file mode 100644 index 000000000000..8e80d30abe87 --- /dev/null +++ b/gfx/vr/VRDisplayLocal.h @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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_DISPLAY_LOCAL_H +#define GFX_VR_DISPLAY_LOCAL_H + +#include "gfxVR.h" +#include "VRDisplayHost.h" + +#if defined(XP_WIN) +#include +#elif defined(XP_MACOSX) +class MacIOSurface; +#endif + +namespace mozilla { +namespace gfx { +class VRThread; + +class VRDisplayLocal : public VRDisplayHost +{ +public: + +#if defined(XP_WIN) + // Subclasses should override this SubmitFrame function. + // Returns true if the SubmitFrame call will block as necessary + // to control timing of the next frame and throttle the render loop + // for the needed framerate. + virtual bool SubmitFrame(ID3D11Texture2D* aSource, + const IntSize& aSize, + const gfx::Rect& aLeftEyeRect, + const gfx::Rect& aRightEyeRect) = 0; +#elif defined(XP_MACOSX) + virtual bool SubmitFrame(MacIOSurface* aMacIOSurface, + const IntSize& aSize, + const gfx::Rect& aLeftEyeRect, + const gfx::Rect& aRightEyeRect) = 0; +#elif defined(MOZ_WIDGET_ANDROID) + virtual bool SubmitFrame(const mozilla::layers::SurfaceTextureDescriptor& aSurface, + const gfx::Rect& aLeftEyeRect, + const gfx::Rect& aRightEyeRect) = 0; +#endif + +protected: + explicit VRDisplayLocal(VRDeviceType aType); + virtual ~VRDisplayLocal(); + +private: + bool SubmitFrame(const layers::SurfaceDescriptor& aTexture, + uint64_t aFrameId, + const gfx::Rect& aLeftEyeRect, + const gfx::Rect& aRightEyeRect) final; +}; + +} // namespace gfx +} // namespace mozilla + +#endif // GFX_VR_DISPLAY_LOCAL_H diff --git a/gfx/vr/VRManager.cpp b/gfx/vr/VRManager.cpp index 4c6abeb0e3c7..95db02a96bce 100644 --- a/gfx/vr/VRManager.cpp +++ b/gfx/vr/VRManager.cpp @@ -231,6 +231,12 @@ VRManager::CheckForInactiveTimeout() TimeDuration duration = TimeStamp::Now() - mLastActiveTime; if (duration.ToMilliseconds() > gfxPrefs::VRInactiveTimeout()) { Shutdown(); + // We must not throttle the next enumeration request + // after an idle timeout, as it may result in the + // user needing to refresh the browser to detect + // VR hardware when leaving and returning to a VR + // site. + mLastDisplayEnumerationTime = TimeStamp(); } } } diff --git a/gfx/vr/external_api/moz_external_vr.h b/gfx/vr/external_api/moz_external_vr.h index 3ed551e3c59f..f2664a66d5a4 100644 --- a/gfx/vr/external_api/moz_external_vr.h +++ b/gfx/vr/external_api/moz_external_vr.h @@ -235,6 +235,8 @@ struct VRDisplayState FloatSize_POD mStageSize; // We can't use a Matrix4x4 here unless we ensure it's a POD type float mSittingToStandingTransform[16]; + uint64_t mLastSubmittedFrameId; + bool mLastSubmittedFrameSuccessful; uint32_t mPresentingGeneration; }; @@ -274,9 +276,8 @@ enum class VRLayerType : uint16_t { enum class VRLayerTextureType : uint16_t { LayerTextureType_None = 0, - LayerTextureType_DirectX = 1, - LayerTextureType_OpenGL = 2, - LayerTextureType_Vulkan = 3 + LayerTextureType_D3D10SurfaceDescriptor = 1, + LayerTextureType_MacIOSurface = 2 }; struct VRLayer_2D_Content @@ -291,6 +292,7 @@ struct VRLayer_Stereo_Immersive void* mTextureHandle; VRLayerTextureType mTextureType; uint64_t mFrameId; + uint64_t mInputFrameId; VRLayerEyeRect mLeftEyeRect; VRLayerEyeRect mRightEyeRect; }; @@ -315,6 +317,7 @@ struct VRBrowserState struct VRSystemState { uint32_t presentingGeneration; + bool enumerationCompleted; VRDisplayState displayState; VRHMDSensorState sensorState; VRControllerState controllerState[kVRControllerMaxCount]; diff --git a/gfx/vr/gfxVRExternal.cpp b/gfx/vr/gfxVRExternal.cpp index 2bd2a6f7fb01..c2702ee3c3e2 100644 --- a/gfx/vr/gfxVRExternal.cpp +++ b/gfx/vr/gfxVRExternal.cpp @@ -102,8 +102,6 @@ VRDisplayExternal::GetSensorState() manager->PullState(&mDisplayInfo.mDisplayState, &mLastSensorState); -// result.CalcViewMatrices(headToEyeTransforms); - mLastSensorState.inputFrameID = mDisplayInfo.mFrameId; return mLastSensorState; } @@ -117,7 +115,15 @@ VRDisplayExternal::StartPresentation() mTelemetry.Clear(); mTelemetry.mPresentationStart = TimeStamp::Now(); - // TODO - Implement this + // Indicate that we are ready to start immersive mode + VRBrowserState state; + memset(&state, 0, sizeof(VRBrowserState)); + state.layerState[0].type = VRLayerType::LayerType_Stereo_Immersive; + VRManager *vm = VRManager::Get(); + VRSystemManagerExternal* manager = vm->GetExternalManager(); + manager->PushState(&state); + + // TODO - Implement telemetry: // mTelemetry.mLastDroppedFrameCount = stats.m_nNumReprojectedFrames; } @@ -128,11 +134,18 @@ VRDisplayExternal::StopPresentation() if (!mIsPresenting) { return; } + mIsPresenting = false; - // TODO - Implement this + // Indicate that we have stopped immersive mode + VRBrowserState state; + memset(&state, 0, sizeof(VRBrowserState)); + VRManager *vm = VRManager::Get(); + VRSystemManagerExternal* manager = vm->GetExternalManager(); + manager->PushState(&state); + + // TODO - Implement telemetry: /* - mIsPresenting = false; const TimeDuration duration = TimeStamp::Now() - mTelemetry.mPresentationStart; Telemetry::Accumulate(Telemetry::WEBVR_USERS_VIEW_IN, 2); Telemetry::Accumulate(Telemetry::WEBVR_TIME_SPENT_VIEWING_IN_OPENVR, @@ -146,47 +159,88 @@ VRDisplayExternal::StopPresentation() */ } +bool +VRDisplayExternal::PopulateLayerTexture(const layers::SurfaceDescriptor& aTexture, + VRLayerTextureType* aTextureType, + void** aTextureHandle) +{ + switch (aTexture.type()) { #if defined(XP_WIN) - -bool -VRDisplayExternal::SubmitFrame(ID3D11Texture2D* aSource, - const IntSize& aSize, - const gfx::Rect& aLeftEyeRect, - const gfx::Rect& aRightEyeRect) -{ - // FINDME! Implement this - return false; -} - + case SurfaceDescriptor::TSurfaceDescriptorD3D10: { + const SurfaceDescriptorD3D10& surf = aTexture.get_SurfaceDescriptorD3D10(); + *aTextureType = VRLayerTextureType::LayerTextureType_D3D10SurfaceDescriptor; + *aTextureHandle = (void *)surf.handle(); + return true; + } #elif defined(XP_MACOSX) - -bool -VRDisplayExternal::SubmitFrame(MacIOSurface* aMacIOSurface, - const IntSize& aSize, - const gfx::Rect& aLeftEyeRect, - const gfx::Rect& aRightEyeRect) -{ - const void* ioSurface = aMacIOSurface->GetIOSurfacePtr(); - bool result = false; - if (ioSurface == nullptr) { - NS_WARNING("VRDisplayExternal::SubmitFrame() could not get an IOSurface"); - } else { - // FINDME! Implement this - } - return result; -} - -#elif defined(MOZ_WIDGET_ANDROID) - -bool -VRDisplayExternal::SubmitFrame(const layers::SurfaceTextureDescriptor& aSurface, - const gfx::Rect& aLeftEyeRect, - const gfx::Rect& aRightEyeRect) { - - return false; -} - + case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface: { + const auto& desc = aTexture.get_SurfaceDescriptorMacIOSurface(); + RefPtr surf = MacIOSurface::LookupSurface(desc.surfaceId(), + desc.scaleFactor(), + !desc.isOpaque()); + if (!surf) { + NS_WARNING("VRDisplayHost::SubmitFrame failed to get a MacIOSurface"); + return false; + } + *aTextureType = VRLayerTextureType::LayerTextureType_MacIOSurface; + *aTextureHandle = (void *)surf->GetIOSurfacePtr(); + return true; + } #endif + default: { + MOZ_ASSERT(false); + return false; + } + } +} + +bool +VRDisplayExternal::SubmitFrame(const layers::SurfaceDescriptor& aTexture, + uint64_t aFrameId, + const gfx::Rect& aLeftEyeRect, + const gfx::Rect& aRightEyeRect) +{ + VRBrowserState state; + memset(&state, 0, sizeof(VRBrowserState)); + state.layerState[0].type = VRLayerType::LayerType_Stereo_Immersive; + VRLayer_Stereo_Immersive& layer = state.layerState[0].layer_stereo_immersive; + if (!PopulateLayerTexture(aTexture, &layer.mTextureType, &layer.mTextureHandle)) { + return false; + } + layer.mFrameId = aFrameId; + layer.mInputFrameId = mDisplayInfo.mLastSensorState[mDisplayInfo.mFrameId % kVRMaxLatencyFrames].inputFrameID; + + layer.mLeftEyeRect.x = aLeftEyeRect.x; + layer.mLeftEyeRect.y = aLeftEyeRect.y; + layer.mLeftEyeRect.width = aLeftEyeRect.width; + layer.mLeftEyeRect.height = aLeftEyeRect.height; + layer.mRightEyeRect.x = aRightEyeRect.x; + layer.mRightEyeRect.y = aRightEyeRect.y; + layer.mRightEyeRect.width = aRightEyeRect.width; + layer.mRightEyeRect.height = aRightEyeRect.height; + + VRManager *vm = VRManager::Get(); + VRSystemManagerExternal* manager = vm->GetExternalManager(); + manager->PushState(&state); + + VRDisplayState displayState; + memset(&displayState, 0, sizeof(VRDisplayState)); + while (displayState.mLastSubmittedFrameId < aFrameId) { + if (manager->PullState(&displayState)) { + if (!displayState.mIsConnected) { + // Service has shut down or hardware has been disconnected + return false; + } + } +#ifdef XP_WIN + Sleep(0); +#else + sleep(0); +#endif + } + + return displayState.mLastSubmittedFrameSuccessful; +} VRControllerExternal::VRControllerExternal(dom::GamepadHand aHand, uint32_t aDisplayID, uint32_t aNumButtons, uint32_t aNumTriggers, @@ -208,8 +262,9 @@ VRControllerExternal::~VRControllerExternal() MOZ_COUNT_DTOR_INHERITED(VRControllerExternal, VRControllerHost); } -VRSystemManagerExternal::VRSystemManagerExternal() - : mExternalShmem(nullptr) +VRSystemManagerExternal::VRSystemManagerExternal(VRExternalShmem* aAPIShmem /* = nullptr*/) + : mExternalShmem(aAPIShmem) + , mSameProcess(aAPIShmem != nullptr) { #if defined(XP_MACOSX) mShmemFD = 0; @@ -323,6 +378,9 @@ VRSystemManagerExternal::CheckForShutdown() void VRSystemManagerExternal::CloseShmem() { + if (mSameProcess) { + return; + } #if defined(XP_MACOSX) if (mExternalShmem) { munmap((void *)mExternalShmem, sizeof(VRExternalShmem)); @@ -347,15 +405,19 @@ VRSystemManagerExternal::CloseShmem() } /*static*/ already_AddRefed -VRSystemManagerExternal::Create() +VRSystemManagerExternal::Create(VRExternalShmem* aAPIShmem /* = nullptr*/) { MOZ_ASSERT(NS_IsMainThread()); - if (!gfxPrefs::VREnabled() || !gfxPrefs::VRExternalEnabled()) { + if (!gfxPrefs::VREnabled()) { return nullptr; } - RefPtr manager = new VRSystemManagerExternal(); + if (!gfxPrefs::VRExternalEnabled() && aAPIShmem == nullptr) { + return nullptr; + } + + RefPtr manager = new VRSystemManagerExternal(aAPIShmem); return manager.forget(); } @@ -397,7 +459,17 @@ VRSystemManagerExternal::Enumerate() OpenShmem(); if (mExternalShmem) { VRDisplayState displayState; - PullState(&displayState); + memset(&displayState, 0, sizeof(VRDisplayState)); + // We must block until enumeration has completed in order + // to signal that the WebVR promise should be resolved at the + // right time. + while (!PullState(&displayState)) { +#ifdef XP_WIN + Sleep(0); +#else + sleep(0); +#endif + } if (displayState.mIsConnected) { mDisplay = new VRDisplayExternal(displayState); } @@ -488,9 +560,10 @@ VRSystemManagerExternal::RemoveControllers() mControllerCount = 0; } -void +bool VRSystemManagerExternal::PullState(VRDisplayState* aDisplayState, VRHMDSensorState* aSensorState /* = nullptr */) { + bool success = false; MOZ_ASSERT(mExternalShmem); if (mExternalShmem) { #if defined(MOZ_WIDGET_ANDROID) @@ -501,16 +574,39 @@ VRSystemManagerExternal::PullState(VRDisplayState* aDisplayState, VRHMDSensorSta } pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->systemMutex)); mDoShutdown = aDisplayState->shutdown; + success = mExternalShmem->state.enumerationCompleted; } #else VRExternalShmem tmp; memcpy(&tmp, (void *)mExternalShmem, sizeof(VRExternalShmem)); - if (tmp.generationA == tmp.generationB && tmp.generationA != 0 && tmp.generationA != -1) { + if (tmp.generationA == tmp.generationB && tmp.generationA != 0 && tmp.generationA != -1 && tmp.state.enumerationCompleted) { memcpy(aDisplayState, &tmp.state.displayState, sizeof(VRDisplayState)); if (aSensorState) { memcpy(aSensorState, &tmp.state.sensorState, sizeof(VRHMDSensorState)); } + success = true; } +#endif // defined(MOZ_WIDGET_ANDROID) + } + + return success; +} + +void +VRSystemManagerExternal::PushState(VRBrowserState* aBrowserState) +{ + MOZ_ASSERT(aBrowserState); + MOZ_ASSERT(mExternalShmem); + if (mExternalShmem) { +#if defined(MOZ_WIDGET_ANDROID) + if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->browserMutex)) == 0) { + memcpy((void *)&(mExternalShmem->browserState), aBrowserState, sizeof(VRBrowserState)); + pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->browserMutex)); + } +#else + mExternalShmem->browserGenerationA++; + memcpy((void *)&(mExternalShmem->browserState), (void *)aBrowserState, sizeof(VRBrowserState)); + mExternalShmem->browserGenerationB++; #endif // defined(MOZ_WIDGET_ANDROID) } } diff --git a/gfx/vr/gfxVRExternal.h b/gfx/vr/gfxVRExternal.h index a1ea19170e47..3db698df1832 100644 --- a/gfx/vr/gfxVRExternal.h +++ b/gfx/vr/gfxVRExternal.h @@ -33,24 +33,14 @@ public: void ZeroSensor() override; protected: - virtual VRHMDSensorState GetSensorState() override; - virtual void StartPresentation() override; - virtual void StopPresentation() override; -#if defined(XP_WIN) - virtual bool SubmitFrame(ID3D11Texture2D* aSource, - const IntSize& aSize, - const gfx::Rect& aLeftEyeRect, - const gfx::Rect& aRightEyeRect) override; -#elif defined(XP_MACOSX) - virtual bool SubmitFrame(MacIOSurface* aMacIOSurface, - const IntSize& aSize, - const gfx::Rect& aLeftEyeRect, - const gfx::Rect& aRightEyeRect) override; -#elif defined(MOZ_WIDGET_ANDROID) - bool SubmitFrame(const layers::SurfaceTextureDescriptor& aSurface, - const gfx::Rect& aLeftEyeRect, - const gfx::Rect& aRightEyeRect) override; -#endif + VRHMDSensorState GetSensorState() override; + void StartPresentation() override; + void StopPresentation() override; + + bool SubmitFrame(const layers::SurfaceDescriptor& aTexture, + uint64_t aFrameId, + const gfx::Rect& aLeftEyeRect, + const gfx::Rect& aRightEyeRect) override; public: explicit VRDisplayExternal(const VRDisplayState& aDisplayState); @@ -59,6 +49,11 @@ protected: virtual ~VRDisplayExternal(); void Destroy(); +private: + bool PopulateLayerTexture(const layers::SurfaceDescriptor& aTexture, + VRLayerTextureType* aTextureType, + void** aTextureHandle); + VRTelemetry mTelemetry; bool mIsPresenting; VRHMDSensorState mLastSensorState; @@ -80,7 +75,7 @@ protected: class VRSystemManagerExternal : public VRSystemManager { public: - static already_AddRefed Create(); + static already_AddRefed Create(VRExternalShmem* aAPIShmem = nullptr); virtual void Destroy() override; virtual void Shutdown() override; @@ -100,10 +95,11 @@ public: double aDuration, const VRManagerPromise& aPromise) override; virtual void StopVibrateHaptic(uint32_t aControllerIdx) override; - void PullState(VRDisplayState* aDisplayState, VRHMDSensorState* aSensorState = nullptr); + bool PullState(VRDisplayState* aDisplayState, VRHMDSensorState* aSensorState = nullptr); + void PushState(VRBrowserState* aBrowserState); protected: - VRSystemManagerExternal(); + explicit VRSystemManagerExternal(VRExternalShmem* aAPIShmem = nullptr); virtual ~VRSystemManagerExternal(); private: @@ -120,6 +116,7 @@ private: #endif volatile VRExternalShmem* mExternalShmem; + bool mSameProcess; void OpenShmem(); void CloseShmem(); diff --git a/gfx/vr/gfxVROSVR.cpp b/gfx/vr/gfxVROSVR.cpp index 2c2ff79e71c8..76fb03e2f7fe 100644 --- a/gfx/vr/gfxVROSVR.cpp +++ b/gfx/vr/gfxVROSVR.cpp @@ -211,13 +211,13 @@ SetFromTanRadians(double left, double right, double bottom, double top) VRDisplayOSVR::VRDisplayOSVR(OSVR_ClientContext* context, OSVR_ClientInterface* iface, OSVR_DisplayConfig* display) - : VRDisplayHost(VRDeviceType::OSVR) + : VRDisplayLocal(VRDeviceType::OSVR) , m_ctx(context) , m_iface(iface) , m_display(display) { - MOZ_COUNT_CTOR_INHERITED(VRDisplayOSVR, VRDisplayHost); + MOZ_COUNT_CTOR_INHERITED(VRDisplayOSVR, VRDisplayLocal); VRDisplayState& state = mDisplayInfo.mDisplayState; state.mIsConnected = true; diff --git a/gfx/vr/gfxVROSVR.h b/gfx/vr/gfxVROSVR.h index 340971eef86c..41e5e7b89c95 100644 --- a/gfx/vr/gfxVROSVR.h +++ b/gfx/vr/gfxVROSVR.h @@ -14,7 +14,7 @@ #include "mozilla/gfx/2D.h" #include "mozilla/EnumeratedArray.h" -#include "VRDisplayHost.h" +#include "VRDisplayLocal.h" #include #include @@ -26,7 +26,7 @@ namespace mozilla { namespace gfx { namespace impl { -class VRDisplayOSVR : public VRDisplayHost +class VRDisplayOSVR : public VRDisplayLocal { public: void ZeroSensor() override; @@ -57,7 +57,7 @@ protected: virtual ~VRDisplayOSVR() { Destroy(); - MOZ_COUNT_DTOR_INHERITED(VRDisplayOSVR, VRDisplayHost); + MOZ_COUNT_DTOR_INHERITED(VRDisplayOSVR, VRDisplayLocal); } void Destroy(); diff --git a/gfx/vr/gfxVROculus.cpp b/gfx/vr/gfxVROculus.cpp index cd08c595d20e..b402f8a32fea 100644 --- a/gfx/vr/gfxVROculus.cpp +++ b/gfx/vr/gfxVROculus.cpp @@ -795,7 +795,7 @@ VROculusSession::UnloadOvrLib() } VRDisplayOculus::VRDisplayOculus(VROculusSession* aSession) - : VRDisplayHost(VRDeviceType::Oculus) + : VRDisplayLocal(VRDeviceType::Oculus) , mSession(aSession) , mQuadVS(nullptr) , mQuadPS(nullptr) @@ -806,7 +806,7 @@ VRDisplayOculus::VRDisplayOculus(VROculusSession* aSession) , mInputLayout(nullptr) , mEyeHeight(OVR_DEFAULT_EYE_HEIGHT) { - MOZ_COUNT_CTOR_INHERITED(VRDisplayOculus, VRDisplayHost); + MOZ_COUNT_CTOR_INHERITED(VRDisplayOculus, VRDisplayLocal); VRDisplayState& state = mDisplayInfo.mDisplayState; strncpy(state.mDisplayName, "Oculus VR HMD", kVRDisplayNameMaxLen); state.mIsConnected = true; @@ -852,7 +852,7 @@ VRDisplayOculus::VRDisplayOculus(VROculusSession* aSession) VRDisplayOculus::~VRDisplayOculus() { Destroy(); - MOZ_COUNT_DTOR_INHERITED(VRDisplayOculus, VRDisplayHost); + MOZ_COUNT_DTOR_INHERITED(VRDisplayOculus, VRDisplayLocal); } void diff --git a/gfx/vr/gfxVROculus.h b/gfx/vr/gfxVROculus.h index 2c49b21e695f..db14631589b5 100644 --- a/gfx/vr/gfxVROculus.h +++ b/gfx/vr/gfxVROculus.h @@ -15,7 +15,7 @@ #include "mozilla/EnumeratedArray.h" #include "gfxVR.h" -#include "VRDisplayHost.h" +#include "VRDisplayLocal.h" #include "ovr_capi_dynamic.h" struct ID3D11Device; @@ -90,7 +90,7 @@ private: void StopRendering(); }; -class VRDisplayOculus : public VRDisplayHost +class VRDisplayOculus : public VRDisplayLocal { public: void ZeroSensor() override; diff --git a/gfx/vr/gfxVROpenVR.cpp b/gfx/vr/gfxVROpenVR.cpp index 5fa586c58f1a..1f74179aee17 100644 --- a/gfx/vr/gfxVROpenVR.cpp +++ b/gfx/vr/gfxVROpenVR.cpp @@ -50,13 +50,13 @@ static const uint32_t kNumOpenVRHaptcs = 1; VRDisplayOpenVR::VRDisplayOpenVR(::vr::IVRSystem *aVRSystem, ::vr::IVRChaperone *aVRChaperone, ::vr::IVRCompositor *aVRCompositor) - : VRDisplayHost(VRDeviceType::OpenVR) + : VRDisplayLocal(VRDeviceType::OpenVR) , mVRSystem(aVRSystem) , mVRChaperone(aVRChaperone) , mVRCompositor(aVRCompositor) , mIsPresenting(false) { - MOZ_COUNT_CTOR_INHERITED(VRDisplayOpenVR, VRDisplayHost); + MOZ_COUNT_CTOR_INHERITED(VRDisplayOpenVR, VRDisplayLocal); VRDisplayState& state = mDisplayInfo.mDisplayState; @@ -98,7 +98,7 @@ VRDisplayOpenVR::VRDisplayOpenVR(::vr::IVRSystem *aVRSystem, VRDisplayOpenVR::~VRDisplayOpenVR() { Destroy(); - MOZ_COUNT_DTOR_INHERITED(VRDisplayOpenVR, VRDisplayHost); + MOZ_COUNT_DTOR_INHERITED(VRDisplayOpenVR, VRDisplayLocal); } void @@ -350,11 +350,11 @@ VRDisplayOpenVR::StopPresentation() } bool -VRDisplayOpenVR::SubmitFrame(void* aTextureHandle, - ::vr::ETextureType aTextureType, - const IntSize& aSize, - const gfx::Rect& aLeftEyeRect, - const gfx::Rect& aRightEyeRect) +VRDisplayOpenVR::SubmitFrameOpenVRHandle(void* aTextureHandle, + ::vr::ETextureType aTextureType, + const IntSize& aSize, + const gfx::Rect& aLeftEyeRect, + const gfx::Rect& aRightEyeRect) { MOZ_ASSERT(mSubmitThread->GetThread() == NS_GetCurrentThread()); if (!mIsPresenting) { @@ -400,9 +400,9 @@ VRDisplayOpenVR::SubmitFrame(ID3D11Texture2D* aSource, const gfx::Rect& aLeftEyeRect, const gfx::Rect& aRightEyeRect) { - return SubmitFrame((void *)aSource, - ::vr::ETextureType::TextureType_DirectX, - aSize, aLeftEyeRect, aRightEyeRect); + return SubmitFrameOpenVRHandle((void *)aSource, + ::vr::ETextureType::TextureType_DirectX, + aSize, aLeftEyeRect, aRightEyeRect); } #elif defined(XP_MACOSX) @@ -418,9 +418,9 @@ VRDisplayOpenVR::SubmitFrame(MacIOSurface* aMacIOSurface, if (ioSurface == nullptr) { NS_WARNING("VRDisplayOpenVR::SubmitFrame() could not get an IOSurface"); } else { - result = SubmitFrame((void *)ioSurface, - ::vr::ETextureType::TextureType_IOSurface, - aSize, aLeftEyeRect, aRightEyeRect); + result = SubmitFrameOpenVRHandle((void *)ioSurface, + ::vr::ETextureType::TextureType_IOSurface, + aSize, aLeftEyeRect, aRightEyeRect); } return result; } diff --git a/gfx/vr/gfxVROpenVR.h b/gfx/vr/gfxVROpenVR.h index df5436285c06..dff9fa9a722e 100644 --- a/gfx/vr/gfxVROpenVR.h +++ b/gfx/vr/gfxVROpenVR.h @@ -17,7 +17,7 @@ #include "openvr.h" #include "gfxVR.h" -#include "VRDisplayHost.h" +#include "VRDisplayLocal.h" #if defined(XP_MACOSX) class MacIOSurface; @@ -28,7 +28,7 @@ class VRThread; namespace impl { -class VRDisplayOpenVR : public VRDisplayHost +class VRDisplayOpenVR : public VRDisplayLocal { public: void ZeroSensor() override; @@ -70,11 +70,11 @@ protected: void UpdateStageParameters(); void UpdateEyeParameters(gfx::Matrix4x4* aHeadToEyeTransforms = nullptr); - bool SubmitFrame(void* aTextureHandle, - ::vr::ETextureType aTextureType, - const IntSize& aSize, - const gfx::Rect& aLeftEyeRect, - const gfx::Rect& aRightEyeRect); + bool SubmitFrameOpenVRHandle(void* aTextureHandle, + ::vr::ETextureType aTextureType, + const IntSize& aSize, + const gfx::Rect& aLeftEyeRect, + const gfx::Rect& aRightEyeRect); }; class VRControllerOpenVR : public VRControllerHost diff --git a/gfx/vr/gfxVRPuppet.cpp b/gfx/vr/gfxVRPuppet.cpp index f279221bad4a..dd4747046b06 100644 --- a/gfx/vr/gfxVRPuppet.cpp +++ b/gfx/vr/gfxVRPuppet.cpp @@ -50,11 +50,11 @@ static const uint32_t kNumPuppetAxis = 3; static const uint32_t kNumPuppetHaptcs = 1; VRDisplayPuppet::VRDisplayPuppet() - : VRDisplayHost(VRDeviceType::Puppet) + : VRDisplayLocal(VRDeviceType::Puppet) , mIsPresenting(false) , mSensorState{} { - MOZ_COUNT_CTOR_INHERITED(VRDisplayPuppet, VRDisplayHost); + MOZ_COUNT_CTOR_INHERITED(VRDisplayPuppet, VRDisplayLocal); VRDisplayState& state = mDisplayInfo.mDisplayState; strncpy(state.mDisplayName, "Puppet HMD", kVRDisplayNameMaxLen); @@ -123,7 +123,7 @@ VRDisplayPuppet::VRDisplayPuppet() VRDisplayPuppet::~VRDisplayPuppet() { - MOZ_COUNT_DTOR_INHERITED(VRDisplayPuppet, VRDisplayHost); + MOZ_COUNT_DTOR_INHERITED(VRDisplayPuppet, VRDisplayLocal); } void diff --git a/gfx/vr/gfxVRPuppet.h b/gfx/vr/gfxVRPuppet.h index 3180402cc10e..3c5f469c855b 100644 --- a/gfx/vr/gfxVRPuppet.h +++ b/gfx/vr/gfxVRPuppet.h @@ -12,7 +12,7 @@ #include "nsRefPtrHashtable.h" #include "gfxVR.h" -#include "VRDisplayHost.h" +#include "VRDisplayLocal.h" #if defined(XP_MACOSX) class MacIOSurface; @@ -21,7 +21,7 @@ namespace mozilla { namespace gfx { namespace impl { -class VRDisplayPuppet : public VRDisplayHost +class VRDisplayPuppet : public VRDisplayLocal { public: void SetDisplayInfo(const VRDisplayInfo& aDisplayInfo); diff --git a/gfx/vr/ipc/VRMessageUtils.h b/gfx/vr/ipc/VRMessageUtils.h index 3276a838cf4c..1f8998ce0196 100644 --- a/gfx/vr/ipc/VRMessageUtils.h +++ b/gfx/vr/ipc/VRMessageUtils.h @@ -47,6 +47,7 @@ struct ParamTraits WriteParam(aMsg, aParam.mIsMounted); WriteParam(aMsg, aParam.mStageSize.width); WriteParam(aMsg, aParam.mStageSize.height); + WriteParam(aMsg, aParam.mLastSubmittedFrameId); WriteParam(aMsg, aParam.mPresentingGeneration); for (int i = 0; i < 16; i++) { // TODO - Should probably memcpy the whole array or @@ -73,6 +74,7 @@ struct ParamTraits !ReadParam(aMsg, aIter, &(aResult->mIsMounted)) || !ReadParam(aMsg, aIter, &(aResult->mStageSize.width)) || !ReadParam(aMsg, aIter, &(aResult->mStageSize.height)) || + !ReadParam(aMsg, aIter, &(aResult->mLastSubmittedFrameId)) || !ReadParam(aMsg, aIter, &(aResult->mPresentingGeneration))) { return false; } diff --git a/gfx/vr/moz.build b/gfx/vr/moz.build index 13f09a5a4689..cb6e9fb57a6c 100644 --- a/gfx/vr/moz.build +++ b/gfx/vr/moz.build @@ -47,6 +47,7 @@ SOURCES += [ 'gfxVRExternal.cpp', 'gfxVRPuppet.cpp', 'VRDisplayHost.cpp', + 'VRDisplayLocal.cpp', ] # Build OpenVR on Windows, Linux, and macOS desktop targets