2015-09-18 00:23:13 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
|
|
|
|
#include "VRManager.h"
|
|
|
|
#include "VRManagerParent.h"
|
|
|
|
#include "gfxVR.h"
|
|
|
|
#include "mozilla/ClearOnShutdown.h"
|
2016-04-13 03:39:28 +03:00
|
|
|
#include "mozilla/dom/VRDisplay.h"
|
2016-02-25 02:54:50 +03:00
|
|
|
#include "mozilla/layers/TextureHost.h"
|
2015-09-18 00:23:13 +03:00
|
|
|
#include "mozilla/unused.h"
|
|
|
|
|
|
|
|
#include "gfxPrefs.h"
|
|
|
|
#include "gfxVR.h"
|
|
|
|
#if defined(XP_WIN)
|
|
|
|
#include "gfxVROculus.h"
|
|
|
|
#endif
|
|
|
|
#if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_LINUX)
|
2016-04-27 00:18:21 +03:00
|
|
|
#include "gfxVROSVR.h"
|
2015-09-18 00:23:13 +03:00
|
|
|
#endif
|
2016-02-25 02:54:50 +03:00
|
|
|
#include "ipc/VRLayerParent.h"
|
|
|
|
|
|
|
|
using namespace mozilla;
|
|
|
|
using namespace mozilla::gfx;
|
|
|
|
using namespace mozilla::layers;
|
|
|
|
using namespace mozilla::gl;
|
2015-09-18 00:23:13 +03:00
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
namespace gfx {
|
|
|
|
|
|
|
|
static StaticRefPtr<VRManager> sVRManagerSingleton;
|
|
|
|
|
|
|
|
/*static*/ void
|
|
|
|
VRManager::ManagerInit()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
|
|
|
if (sVRManagerSingleton == nullptr) {
|
|
|
|
sVRManagerSingleton = new VRManager();
|
|
|
|
ClearOnShutdown(&sVRManagerSingleton);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VRManager::VRManager()
|
|
|
|
: mInitialized(false)
|
|
|
|
{
|
|
|
|
MOZ_COUNT_CTOR(VRManager);
|
|
|
|
MOZ_ASSERT(sVRManagerSingleton == nullptr);
|
|
|
|
|
2016-02-25 02:54:50 +03:00
|
|
|
RefPtr<VRDisplayManager> mgr;
|
2015-09-18 00:23:13 +03:00
|
|
|
|
|
|
|
#if defined(XP_WIN)
|
2016-02-25 02:54:50 +03:00
|
|
|
// The Oculus runtime is supported only on Windows
|
|
|
|
mgr = VRDisplayManagerOculus::Create();
|
2015-09-18 00:23:13 +03:00
|
|
|
if (mgr) {
|
|
|
|
mManagers.AppendElement(mgr);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_LINUX)
|
2016-04-27 00:18:21 +03:00
|
|
|
// OSVR is cross platform compatible
|
2016-02-25 02:54:50 +03:00
|
|
|
mgr = VRDisplayManagerOSVR::Create();
|
2016-04-27 00:18:21 +03:00
|
|
|
if (mgr){
|
|
|
|
mManagers.AppendElement(mgr);
|
|
|
|
}
|
2015-09-18 00:23:13 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
VRManager::~VRManager()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MOZ_ASSERT(!mInitialized);
|
|
|
|
MOZ_COUNT_DTOR(VRManager);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
VRManager::Destroy()
|
|
|
|
{
|
2016-04-13 03:39:28 +03:00
|
|
|
mVRDisplays.Clear();
|
2015-09-18 00:23:13 +03:00
|
|
|
for (uint32_t i = 0; i < mManagers.Length(); ++i) {
|
|
|
|
mManagers[i]->Destroy();
|
|
|
|
}
|
|
|
|
mInitialized = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
VRManager::Init()
|
|
|
|
{
|
|
|
|
for (uint32_t i = 0; i < mManagers.Length(); ++i) {
|
|
|
|
mManagers[i]->Init();
|
|
|
|
}
|
|
|
|
mInitialized = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */VRManager*
|
|
|
|
VRManager::Get()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(sVRManagerSingleton != nullptr);
|
|
|
|
|
|
|
|
return sVRManagerSingleton;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
VRManager::AddVRManagerParent(VRManagerParent* aVRManagerParent)
|
|
|
|
{
|
|
|
|
if (mVRManagerParents.IsEmpty()) {
|
|
|
|
Init();
|
|
|
|
}
|
|
|
|
mVRManagerParents.PutEntry(aVRManagerParent);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
VRManager::RemoveVRManagerParent(VRManagerParent* aVRManagerParent)
|
|
|
|
{
|
|
|
|
mVRManagerParents.RemoveEntry(aVRManagerParent);
|
|
|
|
if (mVRManagerParents.IsEmpty()) {
|
|
|
|
Destroy();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
VRManager::NotifyVsync(const TimeStamp& aVsyncTimestamp)
|
|
|
|
{
|
2016-02-25 02:54:50 +03:00
|
|
|
const double kVRDisplayRefreshMaxDuration = 5000; // milliseconds
|
|
|
|
|
|
|
|
bool bHaveEventListener = false;
|
|
|
|
|
|
|
|
for (auto iter = mVRManagerParents.Iter(); !iter.Done(); iter.Next()) {
|
|
|
|
VRManagerParent *vmp = iter.Get()->GetKey();
|
|
|
|
Unused << vmp->SendNotifyVSync();
|
|
|
|
bHaveEventListener |= vmp->HaveEventListener();
|
|
|
|
}
|
|
|
|
|
2016-04-13 03:39:28 +03:00
|
|
|
for (auto iter = mVRDisplays.Iter(); !iter.Done(); iter.Next()) {
|
2016-02-25 02:54:50 +03:00
|
|
|
gfx::VRDisplayHost* display = iter.UserData();
|
|
|
|
display->NotifyVSync();
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2016-07-05 01:46:49 +03:00
|
|
|
// for events that we must fire such as Window.onvrdisplayconnect
|
2016-02-25 02:54:50 +03:00
|
|
|
// 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();
|
|
|
|
} 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();
|
|
|
|
}
|
|
|
|
}
|
2015-09-18 00:23:13 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-02-25 02:54:50 +03:00
|
|
|
VRManager::NotifyVRVsync(const uint32_t& aDisplayID)
|
2015-09-18 00:23:13 +03:00
|
|
|
{
|
2016-02-25 02:54:50 +03:00
|
|
|
for (auto iter = mVRManagerParents.Iter(); !iter.Done(); iter.Next()) {
|
|
|
|
Unused << iter.Get()->GetKey()->SendNotifyVRVSync(aDisplayID);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
VRManager::RefreshVRDisplays(bool aMustDispatch)
|
|
|
|
{
|
|
|
|
nsTArray<RefPtr<gfx::VRDisplayHost> > displays;
|
2015-09-18 00:23:13 +03:00
|
|
|
|
|
|
|
for (uint32_t i = 0; i < mManagers.Length(); ++i) {
|
2016-02-25 02:54:50 +03:00
|
|
|
mManagers[i]->GetHMDs(displays);
|
2015-09-18 00:23:13 +03:00
|
|
|
}
|
|
|
|
|
2016-02-25 02:54:50 +03:00
|
|
|
bool displayInfoChanged = false;
|
2015-09-18 00:23:13 +03:00
|
|
|
|
2016-02-25 02:54:50 +03:00
|
|
|
if (displays.Length() != mVRDisplays.Count()) {
|
|
|
|
// Catch cases where a VR display has been removed
|
|
|
|
displayInfoChanged = true;
|
2015-09-18 00:23:13 +03:00
|
|
|
}
|
|
|
|
|
2016-02-25 02:54:50 +03:00
|
|
|
for (const auto& display: displays) {
|
|
|
|
if (!GetDisplay(display->GetDisplayInfo().GetDisplayID())) {
|
|
|
|
// This is a new display
|
|
|
|
displayInfoChanged = true;
|
2015-09-18 00:23:13 +03:00
|
|
|
break;
|
|
|
|
}
|
2016-02-25 02:54:50 +03:00
|
|
|
|
|
|
|
if (display->CheckClearDisplayInfoDirty()) {
|
|
|
|
// This display's info has changed
|
|
|
|
displayInfoChanged = true;
|
2015-09-18 00:23:13 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-25 02:54:50 +03:00
|
|
|
if (displayInfoChanged) {
|
2016-04-13 03:39:28 +03:00
|
|
|
mVRDisplays.Clear();
|
2016-02-25 02:54:50 +03:00
|
|
|
for (const auto& display: displays) {
|
|
|
|
mVRDisplays.Put(display->GetDisplayInfo().GetDisplayID(), display);
|
2015-09-18 00:23:13 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-25 02:54:50 +03:00
|
|
|
if (displayInfoChanged || aMustDispatch) {
|
|
|
|
DispatchVRDisplayInfoUpdate();
|
|
|
|
}
|
|
|
|
|
|
|
|
mLastRefreshTime = TimeStamp::Now();
|
2015-09-18 00:23:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-04-13 03:39:28 +03:00
|
|
|
VRManager::DispatchVRDisplayInfoUpdate()
|
2015-09-18 00:23:13 +03:00
|
|
|
{
|
2016-02-25 02:54:50 +03:00
|
|
|
nsTArray<VRDisplayInfo> update;
|
2016-04-13 03:39:28 +03:00
|
|
|
for (auto iter = mVRDisplays.Iter(); !iter.Done(); iter.Next()) {
|
2016-02-25 02:54:50 +03:00
|
|
|
gfx::VRDisplayHost* display = iter.UserData();
|
|
|
|
update.AppendElement(VRDisplayInfo(display->GetDisplayInfo()));
|
2015-09-18 00:23:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
for (auto iter = mVRManagerParents.Iter(); !iter.Done(); iter.Next()) {
|
2016-02-25 02:54:50 +03:00
|
|
|
Unused << iter.Get()->GetKey()->SendUpdateDisplayInfo(update);
|
2015-09-18 00:23:13 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-25 02:54:50 +03:00
|
|
|
RefPtr<gfx::VRDisplayHost>
|
|
|
|
VRManager::GetDisplay(const uint32_t& aDisplayID)
|
2015-09-18 00:23:13 +03:00
|
|
|
{
|
2016-02-25 02:54:50 +03:00
|
|
|
RefPtr<gfx::VRDisplayHost> display;
|
|
|
|
if (mVRDisplays.Get(aDisplayID, getter_AddRefs(display))) {
|
|
|
|
return display;
|
2015-09-18 00:23:13 +03:00
|
|
|
}
|
2016-02-25 02:54:50 +03:00
|
|
|
return nullptr;
|
2015-09-18 00:23:13 +03:00
|
|
|
}
|
|
|
|
|
2016-02-25 02:54:50 +03:00
|
|
|
void
|
|
|
|
VRManager::SubmitFrame(VRLayerParent* aLayer, const int32_t& aInputFrameID,
|
|
|
|
layers::PTextureParent* aTexture, const gfx::Rect& aLeftEyeRect,
|
|
|
|
const gfx::Rect& aRightEyeRect)
|
2015-09-18 00:23:13 +03:00
|
|
|
{
|
2016-02-25 02:54:50 +03:00
|
|
|
TextureHost* th = TextureHost::AsTextureHost(aTexture);
|
|
|
|
mLastFrame = th;
|
|
|
|
RefPtr<VRDisplayHost> display = GetDisplay(aLayer->GetDisplayID());
|
|
|
|
if (display) {
|
|
|
|
display->SubmitFrame(aLayer, aInputFrameID, aTexture, aLeftEyeRect, aRightEyeRect);
|
2015-09-18 00:23:13 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace gfx
|
|
|
|
} // namespace mozilla
|