gecko-dev/gfx/vr/gfxVR.cpp
Kearwood Gilbert d0b2b8da65 Bug 1436791 - Implement gfxVRExternal,r=rbarker
- gfxVRExternal Enables other processes to present
  real or simulated VR hardware to Firefox.
- This functionality is disabled by default, under
  dom.vr.external.enabled.
- VRDisplayInfo, VRControllerInfo, and associated
  structs have been restructured to ensure internal
  state is not exposed via shmem interface.
- Some refactoring to convert structs to
  POD types, enabling them to be located
  in shmem and be memcpy'd.
- Work needed before unpreffing marked
  with "TODO" comments.
MozReview-Commit-ID: FbsusbxuoQ8

--HG--
extra : rebase_source : 8a448169c3f47411c705a4d9fd462a1f9363dfd9
extra : amend_source : e6702549527292e2850d16e8f503f0be9848159f
2018-03-13 17:09:54 -07:00

236 lines
6.8 KiB
C++

/* -*- 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 <math.h>
#include "gfxVR.h"
#include "mozilla/dom/GamepadEventTypes.h"
#include "mozilla/dom/GamepadBinding.h"
#include "VRDisplayHost.h"
#ifndef M_PI
# define M_PI 3.14159265358979323846
#endif
using namespace mozilla;
using namespace mozilla::gfx;
Atomic<uint32_t> VRSystemManager::sDisplayBase(0);
Atomic<uint32_t> VRSystemManager::sControllerBase(0);
/* static */ uint32_t
VRSystemManager::AllocateDisplayID()
{
return ++sDisplayBase;
}
/* static */ uint32_t
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<RefPtr<VRDisplayHost>> 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
{
float upTan = tan(upDegrees * M_PI / 180.0);
float downTan = tan(downDegrees * M_PI / 180.0);
float leftTan = tan(leftDegrees * M_PI / 180.0);
float rightTan = tan(rightDegrees * M_PI / 180.0);
float handednessScale = rightHanded ? -1.0 : 1.0;
float pxscale = 2.0f / (leftTan + rightTan);
float pxoffset = (leftTan - rightTan) * pxscale * 0.5;
float pyscale = 2.0f / (upTan + downTan);
float pyoffset = (upTan - downTan) * pyscale * 0.5;
Matrix4x4 mobj;
float *m = &mobj._11;
m[0*4+0] = pxscale;
m[2*4+0] = pxoffset * handednessScale;
m[1*4+1] = pyscale;
m[2*4+1] = -pyoffset * handednessScale;
m[2*4+2] = zFar / (zNear - zFar) * -handednessScale;
m[3*4+2] = (zFar * zNear) / (zNear - zFar);
m[2*4+3] = handednessScale;
m[3*4+3] = 0.0f;
return mobj;
}
void
VRSystemManager::AddGamepad(const VRControllerInfo& controllerInfo)
{
dom::GamepadAdded a(NS_ConvertUTF8toUTF16(controllerInfo.GetControllerName()),
controllerInfo.GetMappingType(),
controllerInfo.GetHand(),
controllerInfo.GetDisplayID(),
controllerInfo.GetNumButtons(),
controllerInfo.GetNumAxes(),
controllerInfo.GetNumHaptics());
VRManager* vm = VRManager::Get();
vm->NotifyGamepadChange<dom::GamepadAdded>(mControllerCount, a);
}
void
VRSystemManager::RemoveGamepad(uint32_t aIndex)
{
dom::GamepadRemoved a;
VRManager* vm = VRManager::Get();
vm->NotifyGamepadChange<dom::GamepadRemoved>(aIndex, a);
}
void
VRSystemManager::NewButtonEvent(uint32_t aIndex, uint32_t aButton,
bool aPressed, bool aTouched, double aValue)
{
dom::GamepadButtonInformation a(aButton, aValue, aPressed, aTouched);
VRManager* vm = VRManager::Get();
vm->NotifyGamepadChange<dom::GamepadButtonInformation>(aIndex, a);
}
void
VRSystemManager::NewAxisMove(uint32_t aIndex, uint32_t aAxis,
double aValue)
{
dom::GamepadAxisInformation a(aAxis, aValue);
VRManager* vm = VRManager::Get();
vm->NotifyGamepadChange<dom::GamepadAxisInformation>(aIndex, a);
}
void
VRSystemManager::NewPoseState(uint32_t aIndex,
const dom::GamepadPoseState& aPose)
{
dom::GamepadPoseInformation a(aPose);
VRManager* vm = VRManager::Get();
vm->NotifyGamepadChange<dom::GamepadPoseInformation>(aIndex, a);
}
void
VRSystemManager::NewHandChangeEvent(uint32_t aIndex,
const dom::GamepadHand aHand)
{
dom::GamepadHandInformation a(aHand);
VRManager* vm = VRManager::Get();
vm->NotifyGamepadChange<dom::GamepadHandInformation>(aIndex, a);
}
void
VRHMDSensorState::CalcViewMatrices(const gfx::Matrix4x4* aHeadToEyeTransforms)
{
gfx::Matrix4x4 matHead;
if (flags & VRDisplayCapabilityFlags::Cap_Orientation) {
matHead.SetRotationFromQuaternion(gfx::Quaternion(orientation[0], orientation[1],
orientation[2], orientation[3]));
}
matHead.PreTranslate(-position[0], -position[1], -position[2]);
gfx::Matrix4x4 matView = matHead * aHeadToEyeTransforms[VRDisplayState::Eye_Left];
matView.Normalize();
memcpy(leftViewMatrix, matView.components, sizeof(matView.components));
matView = matHead * aHeadToEyeTransforms[VRDisplayState::Eye_Right];
matView.Normalize();
memcpy(rightViewMatrix, matView.components, sizeof(matView.components));
}
const IntSize
VRDisplayInfo::SuggestedEyeResolution() const
{
return IntSize(mDisplayState.mEyeResolution.width,
mDisplayState.mEyeResolution.height);
}
const Point3D
VRDisplayInfo::GetEyeTranslation(uint32_t whichEye) const
{
return Point3D(mDisplayState.mEyeTranslation[whichEye].x,
mDisplayState.mEyeTranslation[whichEye].y,
mDisplayState.mEyeTranslation[whichEye].z);
}
const Size
VRDisplayInfo::GetStageSize() const
{
return Size(mDisplayState.mStageSize.width,
mDisplayState.mStageSize.height);
}
const Matrix4x4
VRDisplayInfo::GetSittingToStandingTransform() const
{
Matrix4x4 m;
// If we could replace Matrix4x4 with a pod type, we could
// use it directly from the VRDisplayInfo struct.
memcpy(m.components, mDisplayState.mSittingToStandingTransform, sizeof(float) * 16);
return m;
}