2017-10-28 02:10:06 +03:00
|
|
|
/* -*- 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
|
2015-09-18 00:23:13 +03:00
|
|
|
* 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"
|
2018-08-21 00:58:28 +03:00
|
|
|
#include "VRGPUChild.h"
|
2017-10-05 13:16:16 +03:00
|
|
|
#include "VRThread.h"
|
2015-09-18 00:23:13 +03:00
|
|
|
#include "gfxVR.h"
|
|
|
|
#include "mozilla/ClearOnShutdown.h"
|
2016-04-13 03:39:28 +03:00
|
|
|
#include "mozilla/dom/VRDisplay.h"
|
2016-10-07 11:58:01 +03:00
|
|
|
#include "mozilla/dom/GamepadEventTypes.h"
|
2016-02-25 02:54:50 +03:00
|
|
|
#include "mozilla/layers/TextureHost.h"
|
2017-10-05 13:16:16 +03:00
|
|
|
#include "mozilla/layers/CompositorThread.h"
|
2016-08-23 07:09:32 +03:00
|
|
|
#include "mozilla/Unused.h"
|
2018-08-07 21:20:34 +03:00
|
|
|
#include "mozilla/gfx/GPUParent.h"
|
2015-09-18 00:23:13 +03:00
|
|
|
|
|
|
|
#include "gfxPrefs.h"
|
|
|
|
#include "gfxVR.h"
|
2018-03-14 03:09:54 +03:00
|
|
|
#include "gfxVRExternal.h"
|
2017-11-01 03:25:40 +03:00
|
|
|
|
2017-03-01 19:04:12 +03:00
|
|
|
#include "gfxVRPuppet.h"
|
2016-02-25 02:54:50 +03:00
|
|
|
#include "ipc/VRLayerParent.h"
|
2018-10-09 05:41:00 +03:00
|
|
|
#if !defined(MOZ_WIDGET_ANDROID)
|
2018-05-08 21:31:28 +03:00
|
|
|
#include "service/VRService.h"
|
|
|
|
#endif
|
2016-02-25 02:54:50 +03:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2018-09-26 01:56:10 +03:00
|
|
|
/**
|
|
|
|
* When VR content is active, we run the tasks at 1ms
|
|
|
|
* intervals, enabling multiple events to be processed
|
|
|
|
* per frame, such as haptic feedback pulses.
|
|
|
|
*/
|
|
|
|
const uint32_t kVRActiveTaskInterval = 1; // milliseconds
|
|
|
|
|
|
|
|
/**
|
|
|
|
* When VR content is inactive, we run the tasks at 100ms
|
|
|
|
* intervals, enabling VR display enumeration and
|
|
|
|
* presentation startup to be relatively responsive
|
|
|
|
* while not consuming unnecessary resources.
|
|
|
|
*/
|
|
|
|
const uint32_t kVRIdleTaskInterval = 100; // milliseconds
|
|
|
|
|
2015-09-18 00:23:13 +03:00
|
|
|
/*static*/ void
|
|
|
|
VRManager::ManagerInit()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
2018-08-07 21:20:34 +03:00
|
|
|
// TODO: We should make VRManager::ManagerInit
|
|
|
|
// be called when entering VR content pages.
|
2015-09-18 00:23:13 +03:00
|
|
|
if (sVRManagerSingleton == nullptr) {
|
|
|
|
sVRManagerSingleton = new VRManager();
|
|
|
|
ClearOnShutdown(&sVRManagerSingleton);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VRManager::VRManager()
|
|
|
|
: mInitialized(false)
|
2018-09-26 01:56:10 +03:00
|
|
|
, mAccumulator100ms(0.0f)
|
2017-10-11 00:42:37 +03:00
|
|
|
, mVRDisplaysRequested(false)
|
|
|
|
, mVRControllersRequested(false)
|
2018-08-21 00:58:28 +03:00
|
|
|
, mVRServiceStarted(false)
|
2018-09-26 01:56:10 +03:00
|
|
|
, mTaskInterval(0)
|
2015-09-18 00:23:13 +03:00
|
|
|
{
|
|
|
|
MOZ_COUNT_CTOR(VRManager);
|
|
|
|
MOZ_ASSERT(sVRManagerSingleton == nullptr);
|
|
|
|
|
2017-01-24 12:49:11 +03:00
|
|
|
RefPtr<VRSystemManager> mgr;
|
2015-09-18 00:23:13 +03:00
|
|
|
|
2018-10-09 05:41:00 +03:00
|
|
|
#if !defined(MOZ_WIDGET_ANDROID)
|
2018-05-08 21:31:28 +03:00
|
|
|
// The VR Service accesses all hardware from a separate process
|
|
|
|
// and replaces the other VRSystemManager when enabled.
|
2018-08-07 21:20:34 +03:00
|
|
|
if (!gfxPrefs::VRProcessEnabled()) {
|
|
|
|
mVRService = VRService::Create();
|
|
|
|
} else if (gfxPrefs::VRProcessEnabled() && XRE_IsGPUProcess()) {
|
|
|
|
gfx::GPUParent* gpu = GPUParent::GetSingleton();
|
|
|
|
MOZ_ASSERT(gpu);
|
|
|
|
Unused << gpu->SendCreateVRProcess();
|
|
|
|
}
|
2018-05-08 21:31:28 +03:00
|
|
|
if (mVRService) {
|
|
|
|
mExternalManager = VRSystemManagerExternal::Create(mVRService->GetAPIShmem());
|
|
|
|
}
|
2018-03-14 03:09:54 +03:00
|
|
|
if (mExternalManager) {
|
2018-05-08 21:31:28 +03:00
|
|
|
mManagers.AppendElement(mExternalManager);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!mExternalManager) {
|
|
|
|
mExternalManager = VRSystemManagerExternal::Create();
|
|
|
|
if (mExternalManager) {
|
2018-03-14 03:09:54 +03:00
|
|
|
mManagers.AppendElement(mExternalManager);
|
2018-05-08 21:31:28 +03:00
|
|
|
}
|
2018-03-14 03:09:54 +03:00
|
|
|
}
|
2016-07-22 22:41:00 +03:00
|
|
|
|
2016-10-24 13:09:11 +03:00
|
|
|
// Enable gamepad extensions while VR is enabled.
|
2016-11-26 18:06:34 +03:00
|
|
|
// Preference only can be set at the Parent process.
|
|
|
|
if (XRE_IsParentProcess() && gfxPrefs::VREnabled()) {
|
2016-10-24 13:09:11 +03:00
|
|
|
Preferences::SetBool("dom.gamepad.extensions.enabled", true);
|
|
|
|
}
|
2015-09-18 00:23:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
VRManager::~VRManager()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MOZ_ASSERT(!mInitialized);
|
|
|
|
MOZ_COUNT_DTOR(VRManager);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
VRManager::Destroy()
|
|
|
|
{
|
2018-09-26 01:56:10 +03:00
|
|
|
StopTasks();
|
2016-04-13 03:39:28 +03:00
|
|
|
mVRDisplays.Clear();
|
2017-01-24 12:49:11 +03:00
|
|
|
mVRControllers.Clear();
|
2015-09-18 00:23:13 +03:00
|
|
|
for (uint32_t i = 0; i < mManagers.Length(); ++i) {
|
|
|
|
mManagers[i]->Destroy();
|
|
|
|
}
|
2018-10-09 05:41:00 +03:00
|
|
|
#if !defined(MOZ_WIDGET_ANDROID)
|
2018-08-21 00:58:28 +03:00
|
|
|
if (mVRService) {
|
|
|
|
mVRService->Stop();
|
|
|
|
mVRService = nullptr;
|
|
|
|
}
|
|
|
|
#endif
|
2015-09-18 00:23:13 +03:00
|
|
|
mInitialized = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2017-03-30 16:35:49 +03:00
|
|
|
VRManager::Shutdown()
|
2015-09-18 00:23:13 +03:00
|
|
|
{
|
2017-03-30 16:35:49 +03:00
|
|
|
mVRDisplays.Clear();
|
|
|
|
mVRControllers.Clear();
|
2015-09-18 00:23:13 +03:00
|
|
|
for (uint32_t i = 0; i < mManagers.Length(); ++i) {
|
2017-03-30 16:35:49 +03:00
|
|
|
mManagers[i]->Shutdown();
|
2015-09-18 00:23:13 +03:00
|
|
|
}
|
2018-10-09 05:41:00 +03:00
|
|
|
#if !defined(MOZ_WIDGET_ANDROID)
|
2018-05-08 21:31:28 +03:00
|
|
|
if (mVRService) {
|
|
|
|
mVRService->Stop();
|
|
|
|
}
|
2018-08-27 23:51:16 +03:00
|
|
|
if (gfxPrefs::VRProcessEnabled() &&
|
|
|
|
VRGPUChild::IsCreated()) {
|
2018-08-21 00:58:28 +03:00
|
|
|
RefPtr<Runnable> task = NS_NewRunnableFunction(
|
|
|
|
"VRGPUChild::SendStopVRService",
|
|
|
|
[] () -> void {
|
|
|
|
VRGPUChild* vrGPUChild = VRGPUChild::Get();
|
|
|
|
vrGPUChild->SendStopVRService();
|
|
|
|
});
|
|
|
|
|
|
|
|
NS_DispatchToMainThread(task.forget());
|
|
|
|
}
|
2018-05-08 21:31:28 +03:00
|
|
|
#endif
|
2018-08-21 00:58:28 +03:00
|
|
|
mVRServiceStarted = false;
|
2017-03-30 16:35:49 +03:00
|
|
|
}
|
2016-10-07 11:58:01 +03:00
|
|
|
|
2017-03-30 16:35:49 +03:00
|
|
|
void
|
|
|
|
VRManager::Init()
|
|
|
|
{
|
2018-10-27 00:51:10 +03:00
|
|
|
StartTasks();
|
2015-09-18 00:23:13 +03:00
|
|
|
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
|
2017-10-11 00:42:37 +03:00
|
|
|
VRManager::UpdateRequestedDevices()
|
2015-09-18 00:23:13 +03:00
|
|
|
{
|
2016-02-25 02:54:50 +03:00
|
|
|
bool bHaveEventListener = false;
|
2017-02-06 11:12:52 +03:00
|
|
|
bool bHaveControllerListener = false;
|
2016-02-25 02:54:50 +03:00
|
|
|
|
|
|
|
for (auto iter = mVRManagerParents.Iter(); !iter.Done(); iter.Next()) {
|
|
|
|
VRManagerParent *vmp = iter.Get()->GetKey();
|
|
|
|
bHaveEventListener |= vmp->HaveEventListener();
|
2017-02-06 11:12:52 +03:00
|
|
|
bHaveControllerListener |= vmp->HaveControllerListener();
|
2016-02-25 02:54:50 +03:00
|
|
|
}
|
|
|
|
|
2017-10-11 00:42:37 +03:00
|
|
|
mVRDisplaysRequested = bHaveEventListener;
|
|
|
|
// We only currently allow controllers to be used when
|
|
|
|
// also activating a VR display
|
|
|
|
mVRControllersRequested = mVRDisplaysRequested && bHaveControllerListener;
|
|
|
|
}
|
2017-03-22 04:58:06 +03:00
|
|
|
|
2017-10-11 00:42:37 +03:00
|
|
|
/**
|
|
|
|
* 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)
|
|
|
|
{
|
|
|
|
for (const auto& manager : mManagers) {
|
|
|
|
manager->NotifyVSync();
|
2015-09-18 00:23:13 +03:00
|
|
|
}
|
2018-09-26 01:56:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
VRManager::StartTasks()
|
|
|
|
{
|
|
|
|
if (!mTaskTimer) {
|
|
|
|
mTaskInterval = GetOptimalTaskInterval();
|
|
|
|
mTaskTimer = NS_NewTimer();
|
2018-10-03 00:17:05 +03:00
|
|
|
mTaskTimer->SetTarget(CompositorThreadHolder::Loop()->SerialEventTarget());
|
2018-09-26 01:56:10 +03:00
|
|
|
mTaskTimer->InitWithNamedFuncCallback(
|
|
|
|
TaskTimerCallback,
|
|
|
|
this,
|
|
|
|
mTaskInterval,
|
|
|
|
nsITimer::TYPE_REPEATING_PRECISE_CAN_SKIP,
|
|
|
|
"VRManager::TaskTimerCallback");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
VRManager::StopTasks()
|
|
|
|
{
|
|
|
|
if (mTaskTimer) {
|
|
|
|
mTaskTimer->Cancel();
|
|
|
|
mTaskTimer = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*static*/ void
|
|
|
|
VRManager::TaskTimerCallback(nsITimer* aTimer, void* aClosure)
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* It is safe to use the pointer passed in aClosure to reference the
|
|
|
|
* VRManager object as the timer is canceled in VRManager::Destroy.
|
|
|
|
* VRManager::Destroy set mInitialized to false, which is asserted
|
|
|
|
* in the VRManager destructor, guaranteeing that this functions
|
|
|
|
* runs if and only if the VRManager object is valid.
|
|
|
|
*/
|
|
|
|
VRManager* self = static_cast<VRManager*>(aClosure);
|
|
|
|
self->RunTasks();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
VRManager::RunTasks()
|
|
|
|
{
|
|
|
|
// Will be called once every 1ms when a VR presentation
|
|
|
|
// is active or once per vsync when a VR presentation is
|
|
|
|
// not active.
|
|
|
|
|
|
|
|
TimeStamp now = TimeStamp::Now();
|
|
|
|
double lastTickMs = mAccumulator100ms;
|
|
|
|
double deltaTime = 0.0f;
|
|
|
|
if (!mLastTickTime.IsNull()) {
|
|
|
|
deltaTime = (now - mLastTickTime).ToMilliseconds();
|
|
|
|
}
|
|
|
|
mAccumulator100ms += deltaTime;
|
|
|
|
mLastTickTime = now;
|
|
|
|
|
|
|
|
if (deltaTime > 0.0f && floor(mAccumulator100ms) != floor(lastTickMs)) {
|
|
|
|
// Even if more than 1 ms has passed, we will only
|
|
|
|
// execute Run1msTasks() once.
|
|
|
|
Run1msTasks(deltaTime);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (floor(mAccumulator100ms * 0.1f) != floor(lastTickMs * 0.1f)) {
|
|
|
|
// Even if more than 10 ms has passed, we will only
|
|
|
|
// execute Run10msTasks() once.
|
|
|
|
Run10msTasks();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mAccumulator100ms >= 100.0f) {
|
|
|
|
// Even if more than 100 ms has passed, we will only
|
|
|
|
// execute Run100msTasks() once.
|
|
|
|
Run100msTasks();
|
|
|
|
mAccumulator100ms = fmod(mAccumulator100ms, 100.0f);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t optimalTaskInterval = GetOptimalTaskInterval();
|
|
|
|
if (mTaskTimer && optimalTaskInterval != mTaskInterval) {
|
|
|
|
mTaskTimer->SetDelay(optimalTaskInterval);
|
|
|
|
mTaskInterval = optimalTaskInterval;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t
|
|
|
|
VRManager::GetOptimalTaskInterval()
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* When either VR content is detected or VR hardware
|
|
|
|
* has already been activated, we schedule tasks more
|
|
|
|
* frequently.
|
|
|
|
*/
|
|
|
|
bool wantGranularTasks = mVRDisplaysRequested ||
|
|
|
|
mVRControllersRequested ||
|
|
|
|
mVRDisplays.Count() ||
|
|
|
|
mVRControllers.Count();
|
|
|
|
if (wantGranularTasks) {
|
|
|
|
return kVRActiveTaskInterval;
|
|
|
|
}
|
|
|
|
|
|
|
|
return kVRIdleTaskInterval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Run1msTasks() is guaranteed not to be
|
|
|
|
* called more than once within 1ms.
|
|
|
|
* When VR is not active, this will be
|
|
|
|
* called once per VSync if it wasn't
|
|
|
|
* called within the last 1ms.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
VRManager::Run1msTasks(double aDeltaTime)
|
|
|
|
{
|
|
|
|
for (const auto& manager : mManagers) {
|
|
|
|
manager->Run1msTasks(aDeltaTime);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto iter = mVRDisplays.Iter(); !iter.Done(); iter.Next()) {
|
|
|
|
gfx::VRDisplayHost* display = iter.UserData();
|
|
|
|
display->Run1msTasks(aDeltaTime);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Run10msTasks() is guaranteed not to be
|
|
|
|
* called more than once within 10ms.
|
|
|
|
* When VR is not active, this will be
|
|
|
|
* called once per VSync if it wasn't
|
|
|
|
* called within the last 10ms.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
VRManager::Run10msTasks()
|
|
|
|
{
|
|
|
|
UpdateRequestedDevices();
|
|
|
|
|
|
|
|
for (const auto& manager : mManagers) {
|
|
|
|
manager->Run10msTasks();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto iter = mVRDisplays.Iter(); !iter.Done(); iter.Next()) {
|
|
|
|
gfx::VRDisplayHost* display = iter.UserData();
|
|
|
|
display->Run10msTasks();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Run100msTasks() is guaranteed not to be
|
|
|
|
* called more than once within 100ms.
|
|
|
|
* When VR is not active, this will be
|
|
|
|
* called once per VSync if it wasn't
|
|
|
|
* called within the last 100ms.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
VRManager::Run100msTasks()
|
|
|
|
{
|
2017-10-11 00:42:37 +03:00
|
|
|
// 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();
|
|
|
|
|
|
|
|
// Update state and enumeration of VR controllers
|
|
|
|
RefreshVRControllers();
|
|
|
|
|
|
|
|
CheckForInactiveTimeout();
|
2018-09-26 01:56:10 +03:00
|
|
|
|
|
|
|
for (const auto& manager : mManagers) {
|
|
|
|
manager->Run100msTasks();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto iter = mVRDisplays.Iter(); !iter.Done(); iter.Next()) {
|
|
|
|
gfx::VRDisplayHost* display = iter.UserData();
|
|
|
|
display->Run100msTasks();
|
|
|
|
}
|
2017-10-11 00:42:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
VRManager::CheckForInactiveTimeout()
|
|
|
|
{
|
2017-04-12 08:12:22 +03:00
|
|
|
// Shut down the VR devices when not in use
|
2017-10-11 00:42:37 +03:00
|
|
|
if (mVRDisplaysRequested || mVRControllersRequested) {
|
2017-04-12 08:12:22 +03:00
|
|
|
// We are using a VR device, keep it alive
|
|
|
|
mLastActiveTime = TimeStamp::Now();
|
2017-10-11 00:42:37 +03:00
|
|
|
}
|
|
|
|
else if (mLastActiveTime.IsNull()) {
|
2017-03-30 16:35:49 +03:00
|
|
|
Shutdown();
|
2017-10-11 00:42:37 +03:00
|
|
|
}
|
|
|
|
else {
|
2017-04-12 08:12:22 +03:00
|
|
|
TimeDuration duration = TimeStamp::Now() - mLastActiveTime;
|
2017-10-11 00:42:37 +03:00
|
|
|
if (duration.ToMilliseconds() > gfxPrefs::VRInactiveTimeout()) {
|
2017-04-12 08:12:22 +03:00
|
|
|
Shutdown();
|
2018-05-08 21:31:28 +03:00
|
|
|
// 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();
|
2017-04-12 08:12:22 +03:00
|
|
|
}
|
2017-03-30 16:35:49 +03:00
|
|
|
}
|
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
|
|
|
{
|
2017-03-22 04:58:06 +03:00
|
|
|
for (const auto& manager: mManagers) {
|
|
|
|
if (manager->GetIsPresenting()) {
|
|
|
|
manager->HandleInput();
|
|
|
|
}
|
2016-12-01 01:24:29 +03:00
|
|
|
}
|
2017-03-22 04:58:06 +03:00
|
|
|
|
2017-05-09 02:01:36 +03:00
|
|
|
RefPtr<VRDisplayHost> display = GetDisplay(aDisplayID);
|
|
|
|
if (display) {
|
|
|
|
display->StartFrame();
|
2016-02-25 02:54:50 +03:00
|
|
|
}
|
2017-05-09 02:01:36 +03:00
|
|
|
|
2018-09-26 01:56:10 +03:00
|
|
|
DispatchVRDisplayInfoUpdate();
|
2016-02-25 02:54:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2017-10-11 00:42:37 +03:00
|
|
|
VRManager::EnumerateVRDisplays()
|
2016-02-25 02:54:50 +03:00
|
|
|
{
|
2017-10-11 00:42:37 +03:00
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
}
|
2017-11-02 07:44:12 +03:00
|
|
|
|
2017-10-11 00:42:37 +03:00
|
|
|
/**
|
|
|
|
* Any VRSystemManager instance may request that no enumeration
|
|
|
|
* should occur, including enumeration from other VRSystemManager
|
|
|
|
* instances.
|
2016-07-22 22:41:00 +03:00
|
|
|
*/
|
2017-10-11 00:42:37 +03:00
|
|
|
for (const auto& manager : mManagers) {
|
|
|
|
if (manager->ShouldInhibitEnumeration()) {
|
|
|
|
return;
|
2017-07-04 23:28:27 +03:00
|
|
|
}
|
2015-09-18 00:23:13 +03:00
|
|
|
}
|
|
|
|
|
2017-10-11 00:42:37 +03:00
|
|
|
/**
|
|
|
|
* If we get this far, don't try again until
|
|
|
|
* the VRDisplayEnumerateInterval elapses
|
|
|
|
*/
|
|
|
|
mLastDisplayEnumerationTime = TimeStamp::Now();
|
|
|
|
|
2018-07-14 03:16:35 +03:00
|
|
|
/**
|
|
|
|
* We must start the VR Service thread
|
|
|
|
* and VR Process before enumeration.
|
|
|
|
* We don't want to start this until we will
|
|
|
|
* actualy enumerate, to avoid continuously
|
|
|
|
* re-launching the thread/process when
|
|
|
|
* no hardware is found or a VR software update
|
|
|
|
* is in progress
|
|
|
|
*/
|
|
|
|
#if !defined(MOZ_WIDGET_ANDROID)
|
|
|
|
// Tell VR process to start VR service.
|
|
|
|
if (gfxPrefs::VRProcessEnabled() && !mVRServiceStarted) {
|
|
|
|
RefPtr<Runnable> task = NS_NewRunnableFunction(
|
|
|
|
"VRGPUChild::SendStartVRService",
|
|
|
|
[] () -> void {
|
|
|
|
VRGPUChild* vrGPUChild = VRGPUChild::Get();
|
|
|
|
vrGPUChild->SendStartVRService();
|
|
|
|
});
|
|
|
|
|
|
|
|
NS_DispatchToMainThread(task.forget());
|
|
|
|
mVRServiceStarted = true;
|
|
|
|
} else if (!gfxPrefs::VRProcessEnabled()){
|
|
|
|
if (mVRService) {
|
|
|
|
mVRService->Start();
|
|
|
|
mVRServiceStarted = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-10-11 00:42:37 +03:00
|
|
|
/**
|
|
|
|
* 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) {
|
2018-10-12 22:29:20 +03:00
|
|
|
EnumerateVRDisplays();
|
|
|
|
}
|
2018-07-14 03:16:35 +03:00
|
|
|
#if !defined(MOZ_WIDGET_ANDROID)
|
|
|
|
if (mVRService) {
|
|
|
|
mVRService->Refresh();
|
|
|
|
}
|
|
|
|
#endif
|
2017-10-11 00:42:37 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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<RefPtr<gfx::VRDisplayHost> > displays;
|
|
|
|
for (const auto& manager: mManagers) {
|
|
|
|
manager->GetHMDs(displays);
|
|
|
|
}
|
|
|
|
|
2016-02-25 02:54:50 +03:00
|
|
|
bool displayInfoChanged = false;
|
2017-07-04 23:28:27 +03:00
|
|
|
bool displaySetChanged = 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
|
2017-07-04 23:28:27 +03:00
|
|
|
displaySetChanged = 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
|
2017-07-04 23:28:27 +03:00
|
|
|
displaySetChanged = 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-04 23:28:27 +03:00
|
|
|
// Rebuild the HashMap if there are additions or removals
|
|
|
|
if (displaySetChanged) {
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-04 23:28:27 +03:00
|
|
|
if (displayInfoChanged || displaySetChanged || aMustDispatch) {
|
2017-11-02 07:44:12 +03:00
|
|
|
DispatchVRDisplayInfoUpdate();
|
2016-02-25 02:54:50 +03:00
|
|
|
}
|
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-07-05 01:52:21 +03:00
|
|
|
GetVRDisplayInfo(update);
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-02 07:44:12 +03:00
|
|
|
|
2016-07-05 01:52:21 +03:00
|
|
|
/**
|
|
|
|
* Get any VR displays that have already been enumerated without
|
|
|
|
* activating any new devices.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
VRManager::GetVRDisplayInfo(nsTArray<VRDisplayInfo>& aDisplayInfo)
|
|
|
|
{
|
|
|
|
aDisplayInfo.Clear();
|
|
|
|
for (auto iter = mVRDisplays.Iter(); !iter.Done(); iter.Next()) {
|
|
|
|
gfx::VRDisplayHost* display = iter.UserData();
|
|
|
|
aDisplayInfo.AppendElement(VRDisplayInfo(display->GetDisplayInfo()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-10-07 11:58:01 +03:00
|
|
|
RefPtr<gfx::VRControllerHost>
|
|
|
|
VRManager::GetController(const uint32_t& aControllerID)
|
|
|
|
{
|
|
|
|
RefPtr<gfx::VRControllerHost> controller;
|
|
|
|
if (mVRControllers.Get(aControllerID, getter_AddRefs(controller))) {
|
|
|
|
return controller;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
VRManager::GetVRControllerInfo(nsTArray<VRControllerInfo>& aControllerInfo)
|
|
|
|
{
|
|
|
|
aControllerInfo.Clear();
|
|
|
|
for (auto iter = mVRControllers.Iter(); !iter.Done(); iter.Next()) {
|
|
|
|
gfx::VRControllerHost* controller = iter.UserData();
|
|
|
|
aControllerInfo.AppendElement(VRControllerInfo(controller->GetControllerInfo()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-07 12:00:45 +03:00
|
|
|
void
|
|
|
|
VRManager::RefreshVRControllers()
|
|
|
|
{
|
2016-12-01 09:16:16 +03:00
|
|
|
ScanForControllers();
|
2016-11-28 11:57:58 +03:00
|
|
|
|
2017-10-11 00:42:37 +03:00
|
|
|
nsTArray<RefPtr<gfx::VRControllerHost>> controllers;
|
|
|
|
|
2017-01-24 12:49:11 +03:00
|
|
|
for (uint32_t i = 0; i < mManagers.Length()
|
2016-10-07 12:00:45 +03:00
|
|
|
&& controllers.Length() == 0; ++i) {
|
2017-01-24 12:49:11 +03:00
|
|
|
mManagers[i]->GetControllers(controllers);
|
2016-10-07 12:00:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
bool controllerInfoChanged = false;
|
|
|
|
|
|
|
|
if (controllers.Length() != mVRControllers.Count()) {
|
|
|
|
// Catch cases where VR controllers has been removed
|
|
|
|
controllerInfoChanged = true;
|
|
|
|
}
|
|
|
|
|
2017-03-22 04:58:06 +03:00
|
|
|
for (const auto& controller: controllers) {
|
2016-10-07 12:00:45 +03:00
|
|
|
if (!GetController(controller->GetControllerInfo().GetControllerID())) {
|
|
|
|
// This is a new controller
|
|
|
|
controllerInfoChanged = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (controllerInfoChanged) {
|
|
|
|
mVRControllers.Clear();
|
2017-03-22 04:58:06 +03:00
|
|
|
for (const auto& controller: controllers) {
|
2016-10-07 12:00:45 +03:00
|
|
|
mVRControllers.Put(controller->GetControllerInfo().GetControllerID(),
|
|
|
|
controller);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-07 11:58:01 +03:00
|
|
|
void
|
2016-12-01 09:16:16 +03:00
|
|
|
VRManager::ScanForControllers()
|
2016-10-07 11:58:01 +03:00
|
|
|
{
|
2017-10-11 00:42:37 +03:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2017-01-24 12:49:11 +03:00
|
|
|
for (uint32_t i = 0; i < mManagers.Length(); ++i) {
|
|
|
|
mManagers[i]->ScanForControllers();
|
2016-10-07 11:58:01 +03:00
|
|
|
}
|
2017-10-11 00:42:37 +03:00
|
|
|
|
|
|
|
mLastControllerEnumerationTime = TimeStamp::Now();
|
2016-10-07 11:58:01 +03:00
|
|
|
}
|
|
|
|
|
2016-12-01 09:16:16 +03:00
|
|
|
void
|
|
|
|
VRManager::RemoveControllers()
|
|
|
|
{
|
2017-01-24 12:49:11 +03:00
|
|
|
for (uint32_t i = 0; i < mManagers.Length(); ++i) {
|
|
|
|
mManagers[i]->RemoveControllers();
|
2016-12-01 09:16:16 +03:00
|
|
|
}
|
|
|
|
mVRControllers.Clear();
|
|
|
|
}
|
|
|
|
|
2017-03-03 20:27:22 +03:00
|
|
|
void
|
|
|
|
VRManager::CreateVRTestSystem()
|
|
|
|
{
|
2017-11-22 01:18:16 +03:00
|
|
|
if (mPuppetManager) {
|
|
|
|
mPuppetManager->ClearTestDisplays();
|
2017-03-03 20:27:22 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-11-22 01:18:16 +03:00
|
|
|
mPuppetManager = VRSystemManagerPuppet::Create();
|
|
|
|
mManagers.AppendElement(mPuppetManager);
|
|
|
|
}
|
|
|
|
|
|
|
|
VRSystemManagerPuppet*
|
|
|
|
VRManager::GetPuppetManager()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(mPuppetManager);
|
|
|
|
return mPuppetManager;
|
2017-03-03 20:27:22 +03:00
|
|
|
}
|
|
|
|
|
2018-03-14 03:09:54 +03:00
|
|
|
VRSystemManagerExternal*
|
|
|
|
VRManager::GetExternalManager()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(mExternalManager);
|
|
|
|
return mExternalManager;
|
|
|
|
}
|
|
|
|
|
2016-10-07 11:58:01 +03:00
|
|
|
template<class T>
|
|
|
|
void
|
2017-07-17 06:44:39 +03:00
|
|
|
VRManager::NotifyGamepadChange(uint32_t aIndex, const T& aInfo)
|
2016-10-07 11:58:01 +03:00
|
|
|
{
|
2017-07-17 06:44:39 +03:00
|
|
|
dom::GamepadChangeEventBody body(aInfo);
|
|
|
|
dom::GamepadChangeEvent e(aIndex, dom::GamepadServiceType::VR, body);
|
2016-10-07 11:58:01 +03:00
|
|
|
|
|
|
|
for (auto iter = mVRManagerParents.Iter(); !iter.Done(); iter.Next()) {
|
2017-11-02 07:44:12 +03:00
|
|
|
Unused << iter.Get()->GetKey()->SendGamepadUpdate(e);
|
2016-10-07 11:58:01 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-02 09:57:58 +03:00
|
|
|
void
|
|
|
|
VRManager::VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
|
2017-11-30 14:37:07 +03:00
|
|
|
double aIntensity, double aDuration,
|
|
|
|
const VRManagerPromise& aPromise)
|
2017-02-02 09:59:44 +03:00
|
|
|
|
2017-02-02 09:57:58 +03:00
|
|
|
{
|
|
|
|
for (uint32_t i = 0; i < mManagers.Length(); ++i) {
|
|
|
|
mManagers[i]->VibrateHaptic(aControllerIdx, aHapticIndex,
|
2017-11-30 14:37:07 +03:00
|
|
|
aIntensity, aDuration, aPromise);
|
2017-02-02 09:57:58 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-07 05:17:57 +03:00
|
|
|
void
|
|
|
|
VRManager::StopVibrateHaptic(uint32_t aControllerIdx)
|
|
|
|
{
|
|
|
|
for (const auto& manager: mManagers) {
|
|
|
|
manager->StopVibrateHaptic(aControllerIdx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2017-11-30 14:37:07 +03:00
|
|
|
VRManager::NotifyVibrateHapticCompleted(const VRManagerPromise& aPromise)
|
2017-03-07 05:17:57 +03:00
|
|
|
{
|
2017-11-30 14:37:07 +03:00
|
|
|
aPromise.mParent->SendReplyGamepadVibrateHaptic(aPromise.mPromiseID);
|
2017-03-07 05:17:57 +03:00
|
|
|
}
|
|
|
|
|
2017-05-23 11:55:30 +03:00
|
|
|
void
|
|
|
|
VRManager::DispatchSubmitFrameResult(uint32_t aDisplayID, const VRSubmitFrameResultInfo& aResult)
|
|
|
|
{
|
|
|
|
for (auto iter = mVRManagerParents.Iter(); !iter.Done(); iter.Next()) {
|
|
|
|
Unused << iter.Get()->GetKey()->SendDispatchSubmitFrameResult(aDisplayID, aResult);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-31 04:41:25 +03:00
|
|
|
void
|
|
|
|
VRManager::StartVRNavigation(const uint32_t& aDisplayID)
|
|
|
|
{
|
|
|
|
RefPtr<VRDisplayHost> display = GetDisplay(aDisplayID);
|
|
|
|
if (display) {
|
|
|
|
display->StartVRNavigation();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
VRManager::StopVRNavigation(const uint32_t& aDisplayID, const TimeDuration& aTimeout)
|
|
|
|
{
|
|
|
|
RefPtr<VRDisplayHost> display = GetDisplay(aDisplayID);
|
|
|
|
if (display) {
|
|
|
|
display->StopVRNavigation(aTimeout);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-18 00:23:13 +03:00
|
|
|
} // namespace gfx
|
|
|
|
} // namespace mozilla
|