зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1466699 - Implement VRService thread r=daoshengmu
- Refactored gfxVROpenVR to use gfxVRExternal interface from the VR Service. Existing gfxVROpenVR left in place (for now) to allow VR service to be enabled or disabled by pref. - The VR service, containing gfxVROpenVR, is to run in-process within its own thread first, then to be later moved to its own process. - Fixed periodic immersive mode flicker that occured due to HMD pose and HMD state being separately sampled from the Shmem. It was possible to advance a frame without also getting an updated pose if a dirty copy of the shmem was detected. MozReview-Commit-ID: IvpJErmi5kF --HG-- extra : rebase_source : 0e21d3414a13dc514c3035f2bd5f6adc365b465d
This commit is contained in:
Родитель
aece1534ef
Коммит
d1989d114c
|
@ -390,6 +390,7 @@ private:
|
|||
DECL_GFX_PREF(Live, "dom.vr.puppet.enabled", VRPuppetEnabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "dom.vr.puppet.submitframe", VRPuppetSubmitFrame, uint32_t, 0);
|
||||
DECL_GFX_PREF(Live, "dom.vr.display.rafMaxDuration", VRDisplayRafMaxDuration, uint32_t, 50);
|
||||
DECL_GFX_PREF(Once, "dom.vr.service.enabled", VRServiceEnabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "dom.w3c_pointer_events.enabled", PointerEventsEnabled, bool, false);
|
||||
|
||||
DECL_GFX_PREF(Live, "general.smoothScroll", SmoothScrollEnabled, bool, true);
|
||||
|
|
|
@ -29,6 +29,9 @@
|
|||
|
||||
#include "gfxVRPuppet.h"
|
||||
#include "ipc/VRLayerParent.h"
|
||||
#if !defined(MOZ_WIDGET_ANDROID)
|
||||
#include "service/VRService.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
|
@ -74,31 +77,50 @@ VRManager::VRManager()
|
|||
* OSVR will be used if Oculus SDK and OpenVR don't detect any HMDS,
|
||||
* to support everyone else.
|
||||
*/
|
||||
mExternalManager = VRSystemManagerExternal::Create();
|
||||
|
||||
#if !defined(MOZ_WIDGET_ANDROID)
|
||||
// The VR Service accesses all hardware from a separate process
|
||||
// and replaces the other VRSystemManager when enabled.
|
||||
mVRService = VRService::Create();
|
||||
if (mVRService) {
|
||||
mExternalManager = VRSystemManagerExternal::Create(mVRService->GetAPIShmem());
|
||||
}
|
||||
if (mExternalManager) {
|
||||
mManagers.AppendElement(mExternalManager);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!mExternalManager) {
|
||||
mExternalManager = VRSystemManagerExternal::Create();
|
||||
if (mExternalManager) {
|
||||
mManagers.AppendElement(mExternalManager);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(XP_WIN)
|
||||
// The Oculus runtime is supported only on Windows
|
||||
mgr = VRSystemManagerOculus::Create();
|
||||
if (mgr) {
|
||||
mManagers.AppendElement(mgr);
|
||||
if (!mVRService) {
|
||||
// The Oculus runtime is supported only on Windows
|
||||
mgr = VRSystemManagerOculus::Create();
|
||||
if (mgr) {
|
||||
mManagers.AppendElement(mgr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(XP_WIN) || defined(XP_MACOSX) || (defined(XP_LINUX) && !defined(MOZ_WIDGET_ANDROID))
|
||||
// OpenVR is cross platform compatible
|
||||
mgr = VRSystemManagerOpenVR::Create();
|
||||
if (mgr) {
|
||||
mManagers.AppendElement(mgr);
|
||||
}
|
||||
|
||||
// OSVR is cross platform compatible
|
||||
mgr = VRSystemManagerOSVR::Create();
|
||||
if (mgr) {
|
||||
if (!mVRService) {
|
||||
// OpenVR is cross platform compatible
|
||||
mgr = VRSystemManagerOpenVR::Create();
|
||||
if (mgr) {
|
||||
mManagers.AppendElement(mgr);
|
||||
}
|
||||
}
|
||||
|
||||
// OSVR is cross platform compatible
|
||||
mgr = VRSystemManagerOSVR::Create();
|
||||
if (mgr) {
|
||||
mManagers.AppendElement(mgr);
|
||||
}
|
||||
} // !mVRService
|
||||
#endif
|
||||
|
||||
// Enable gamepad extensions while VR is enabled.
|
||||
|
@ -135,6 +157,11 @@ VRManager::Shutdown()
|
|||
for (uint32_t i = 0; i < mManagers.Length(); ++i) {
|
||||
mManagers[i]->Shutdown();
|
||||
}
|
||||
#if !defined(MOZ_WIDGET_ANDROID)
|
||||
if (mVRService) {
|
||||
mVRService->Stop();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -321,6 +348,11 @@ VRManager::RefreshVRDisplays(bool aMustDispatch)
|
|||
* or interrupt other VR activities.
|
||||
*/
|
||||
if (mVRDisplaysRequested || aMustDispatch) {
|
||||
#if !defined(MOZ_WIDGET_ANDROID)
|
||||
if (mVRService) {
|
||||
mVRService->Start();
|
||||
}
|
||||
#endif
|
||||
EnumerateVRDisplays();
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,9 @@ namespace gfx {
|
|||
class VRLayerParent;
|
||||
class VRManagerParent;
|
||||
class VRDisplayHost;
|
||||
#if !defined(MOZ_WIDGET_ANDROID)
|
||||
class VRService;
|
||||
#endif
|
||||
class VRSystemManagerPuppet;
|
||||
class VRSystemManagerExternal;
|
||||
|
||||
|
@ -92,6 +95,9 @@ private:
|
|||
TimeStamp mLastActiveTime;
|
||||
RefPtr<VRSystemManagerPuppet> mPuppetManager;
|
||||
RefPtr<VRSystemManagerExternal> mExternalManager;
|
||||
#if !defined(MOZ_WIDGET_ANDROID)
|
||||
RefPtr<VRService> mVRService;
|
||||
#endif
|
||||
bool mVRDisplaysRequested;
|
||||
bool mVRControllersRequested;
|
||||
};
|
||||
|
|
|
@ -91,17 +91,12 @@ VRDisplayExternal::Refresh()
|
|||
VRManager *vm = VRManager::Get();
|
||||
VRSystemManagerExternal* manager = vm->GetExternalManager();
|
||||
|
||||
manager->PullState(&mDisplayInfo.mDisplayState);
|
||||
manager->PullState(&mDisplayInfo.mDisplayState, &mLastSensorState);
|
||||
}
|
||||
|
||||
VRHMDSensorState
|
||||
VRDisplayExternal::GetSensorState()
|
||||
{
|
||||
VRManager *vm = VRManager::Get();
|
||||
VRSystemManagerExternal* manager = vm->GetExternalManager();
|
||||
|
||||
manager->PullState(&mDisplayInfo.mDisplayState, &mLastSensorState);
|
||||
|
||||
return mLastSensorState;
|
||||
}
|
||||
|
||||
|
@ -226,7 +221,7 @@ VRDisplayExternal::SubmitFrame(const layers::SurfaceDescriptor& aTexture,
|
|||
VRDisplayState displayState;
|
||||
memset(&displayState, 0, sizeof(VRDisplayState));
|
||||
while (displayState.mLastSubmittedFrameId < aFrameId) {
|
||||
if (manager->PullState(&displayState)) {
|
||||
if (manager->PullState(&displayState, &mLastSensorState)) {
|
||||
if (!displayState.mIsConnected) {
|
||||
// Service has shut down or hardware has been disconnected
|
||||
return false;
|
||||
|
|
|
@ -54,6 +54,7 @@ SOURCES += [
|
|||
if CONFIG['OS_TARGET'] in ('WINNT', 'Linux', 'Darwin'):
|
||||
DIRS += [
|
||||
'openvr',
|
||||
'service',
|
||||
]
|
||||
SOURCES += [
|
||||
'gfxVROpenVR.cpp',
|
||||
|
|
|
@ -0,0 +1,487 @@
|
|||
#include "OpenVRSession.h"
|
||||
|
||||
#if defined(XP_WIN)
|
||||
#include <d3d11.h>
|
||||
#include "mozilla/gfx/DeviceManagerDx.h"
|
||||
#endif // defined(XP_WIN)
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
#include "mozilla/dom/GamepadEventTypes.h"
|
||||
#include "mozilla/dom/GamepadBinding.h"
|
||||
#endif
|
||||
|
||||
#if !defined(M_PI)
|
||||
#define M_PI 3.14159265358979323846264338327950288
|
||||
#endif
|
||||
|
||||
#define BTN_MASK_FROM_ID(_id) \
|
||||
::vr::ButtonMaskFromId(vr::EVRButtonId::_id)
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
OpenVRSession::OpenVRSession()
|
||||
: VRSession()
|
||||
, mVRSystem(nullptr)
|
||||
, mVRChaperone(nullptr)
|
||||
, mVRCompositor(nullptr)
|
||||
, mShouldQuit(false)
|
||||
{
|
||||
}
|
||||
|
||||
OpenVRSession::~OpenVRSession()
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
bool
|
||||
OpenVRSession::Initialize(mozilla::gfx::VRSystemState& aSystemState)
|
||||
{
|
||||
if (mVRSystem != nullptr) {
|
||||
// Already initialized
|
||||
return true;
|
||||
}
|
||||
if (!::vr::VR_IsHmdPresent()) {
|
||||
fprintf(stderr, "No HMD detected, VR_IsHmdPresent returned false.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
::vr::HmdError err;
|
||||
|
||||
::vr::VR_Init(&err, ::vr::EVRApplicationType::VRApplication_Scene);
|
||||
if (err) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mVRSystem = (::vr::IVRSystem *)::vr::VR_GetGenericInterface(::vr::IVRSystem_Version, &err);
|
||||
if (err || !mVRSystem) {
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
mVRChaperone = (::vr::IVRChaperone *)::vr::VR_GetGenericInterface(::vr::IVRChaperone_Version, &err);
|
||||
if (err || !mVRChaperone) {
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
mVRCompositor = (::vr::IVRCompositor*)::vr::VR_GetGenericInterface(::vr::IVRCompositor_Version, &err);
|
||||
if (err || !mVRCompositor) {
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(XP_WIN)
|
||||
if (!CreateD3DObjects()) {
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Configure coordinate system
|
||||
mVRCompositor->SetTrackingSpace(::vr::TrackingUniverseSeated);
|
||||
|
||||
if (!InitState(aSystemState)) {
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Succeeded
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(XP_WIN)
|
||||
bool
|
||||
OpenVRSession::CreateD3DObjects()
|
||||
{
|
||||
RefPtr<ID3D11Device> device = gfx::DeviceManagerDx::Get()->GetVRDevice();
|
||||
if (!device) {
|
||||
return false;
|
||||
}
|
||||
if (!CreateD3DContext(device)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
OpenVRSession::Shutdown()
|
||||
{
|
||||
if (mVRSystem || mVRCompositor || mVRSystem) {
|
||||
::vr::VR_Shutdown();
|
||||
mVRCompositor = nullptr;
|
||||
mVRChaperone = nullptr;
|
||||
mVRSystem = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
OpenVRSession::InitState(VRSystemState& aSystemState)
|
||||
{
|
||||
VRDisplayState& state = aSystemState.displayState;
|
||||
strncpy(state.mDisplayName, "OpenVR HMD", kVRDisplayNameMaxLen);
|
||||
state.mIsConnected = mVRSystem->IsTrackedDeviceConnected(::vr::k_unTrackedDeviceIndex_Hmd);
|
||||
state.mIsMounted = false;
|
||||
state.mCapabilityFlags = (VRDisplayCapabilityFlags)((int)VRDisplayCapabilityFlags::Cap_None |
|
||||
(int)VRDisplayCapabilityFlags::Cap_Orientation |
|
||||
(int)VRDisplayCapabilityFlags::Cap_Position |
|
||||
(int)VRDisplayCapabilityFlags::Cap_External |
|
||||
(int)VRDisplayCapabilityFlags::Cap_Present |
|
||||
(int)VRDisplayCapabilityFlags::Cap_StageParameters);
|
||||
|
||||
::vr::ETrackedPropertyError err;
|
||||
bool bHasProximitySensor = mVRSystem->GetBoolTrackedDeviceProperty(::vr::k_unTrackedDeviceIndex_Hmd, ::vr::Prop_ContainsProximitySensor_Bool, &err);
|
||||
if (err == ::vr::TrackedProp_Success && bHasProximitySensor) {
|
||||
state.mCapabilityFlags = (VRDisplayCapabilityFlags)((int)state.mCapabilityFlags | (int)VRDisplayCapabilityFlags::Cap_MountDetection);
|
||||
}
|
||||
|
||||
uint32_t w, h;
|
||||
mVRSystem->GetRecommendedRenderTargetSize(&w, &h);
|
||||
state.mEyeResolution.width = w;
|
||||
state.mEyeResolution.height = h;
|
||||
|
||||
// default to an identity quaternion
|
||||
aSystemState.sensorState.orientation[3] = 1.0f;
|
||||
|
||||
UpdateStageParameters(state);
|
||||
UpdateEyeParameters(state);
|
||||
|
||||
VRHMDSensorState& sensorState = aSystemState.sensorState;
|
||||
sensorState.flags = (VRDisplayCapabilityFlags)(
|
||||
(int)VRDisplayCapabilityFlags::Cap_Orientation |
|
||||
(int)VRDisplayCapabilityFlags::Cap_Position);
|
||||
sensorState.orientation[3] = 1.0f; // Default to an identity quaternion
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
OpenVRSession::UpdateStageParameters(VRDisplayState& state)
|
||||
{
|
||||
float sizeX = 0.0f;
|
||||
float sizeZ = 0.0f;
|
||||
if (mVRChaperone->GetPlayAreaSize(&sizeX, &sizeZ)) {
|
||||
::vr::HmdMatrix34_t t = mVRSystem->GetSeatedZeroPoseToStandingAbsoluteTrackingPose();
|
||||
state.mStageSize.width = sizeX;
|
||||
state.mStageSize.height = sizeZ;
|
||||
|
||||
state.mSittingToStandingTransform[0] = t.m[0][0];
|
||||
state.mSittingToStandingTransform[1] = t.m[1][0];
|
||||
state.mSittingToStandingTransform[2] = t.m[2][0];
|
||||
state.mSittingToStandingTransform[3] = 0.0f;
|
||||
|
||||
state.mSittingToStandingTransform[4] = t.m[0][1];
|
||||
state.mSittingToStandingTransform[5] = t.m[1][1];
|
||||
state.mSittingToStandingTransform[6] = t.m[2][1];
|
||||
state.mSittingToStandingTransform[7] = 0.0f;
|
||||
|
||||
state.mSittingToStandingTransform[8] = t.m[0][2];
|
||||
state.mSittingToStandingTransform[9] = t.m[1][2];
|
||||
state.mSittingToStandingTransform[10] = t.m[2][2];
|
||||
state.mSittingToStandingTransform[11] = 0.0f;
|
||||
|
||||
state.mSittingToStandingTransform[12] = t.m[0][3];
|
||||
state.mSittingToStandingTransform[13] = t.m[1][3];
|
||||
state.mSittingToStandingTransform[14] = t.m[2][3];
|
||||
state.mSittingToStandingTransform[15] = 1.0f;
|
||||
} else {
|
||||
// If we fail, fall back to reasonable defaults.
|
||||
// 1m x 1m space, 0.75m high in seated position
|
||||
|
||||
state.mStageSize.width = 1.0f;
|
||||
state.mStageSize.height = 1.0f;
|
||||
|
||||
state.mSittingToStandingTransform[0] = 1.0f;
|
||||
state.mSittingToStandingTransform[1] = 0.0f;
|
||||
state.mSittingToStandingTransform[2] = 0.0f;
|
||||
state.mSittingToStandingTransform[3] = 0.0f;
|
||||
|
||||
state.mSittingToStandingTransform[4] = 0.0f;
|
||||
state.mSittingToStandingTransform[5] = 1.0f;
|
||||
state.mSittingToStandingTransform[6] = 0.0f;
|
||||
state.mSittingToStandingTransform[7] = 0.0f;
|
||||
|
||||
state.mSittingToStandingTransform[8] = 0.0f;
|
||||
state.mSittingToStandingTransform[9] = 0.0f;
|
||||
state.mSittingToStandingTransform[10] = 1.0f;
|
||||
state.mSittingToStandingTransform[11] = 0.0f;
|
||||
|
||||
state.mSittingToStandingTransform[12] = 0.0f;
|
||||
state.mSittingToStandingTransform[13] = 0.75f;
|
||||
state.mSittingToStandingTransform[14] = 0.0f;
|
||||
state.mSittingToStandingTransform[15] = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
OpenVRSession::UpdateEyeParameters(VRDisplayState& state, gfx::Matrix4x4* headToEyeTransforms /* = nullptr */)
|
||||
{
|
||||
for (uint32_t eye = 0; eye < 2; ++eye) {
|
||||
::vr::HmdMatrix34_t eyeToHead = mVRSystem->GetEyeToHeadTransform(static_cast<::vr::Hmd_Eye>(eye));
|
||||
state.mEyeTranslation[eye].x = eyeToHead.m[0][3];
|
||||
state.mEyeTranslation[eye].y = eyeToHead.m[1][3];
|
||||
state.mEyeTranslation[eye].z = eyeToHead.m[2][3];
|
||||
|
||||
float left, right, up, down;
|
||||
mVRSystem->GetProjectionRaw(static_cast<::vr::Hmd_Eye>(eye), &left, &right, &up, &down);
|
||||
state.mEyeFOV[eye].upDegrees = atan(-up) * 180.0 / M_PI;
|
||||
state.mEyeFOV[eye].rightDegrees = atan(right) * 180.0 / M_PI;
|
||||
state.mEyeFOV[eye].downDegrees = atan(down) * 180.0 / M_PI;
|
||||
state.mEyeFOV[eye].leftDegrees = atan(-left) * 180.0 / M_PI;
|
||||
|
||||
if (headToEyeTransforms) {
|
||||
Matrix4x4 pose;
|
||||
// NOTE! eyeToHead.m is a 3x4 matrix, not 4x4. But
|
||||
// because of its arrangement, we can copy the 12 elements in and
|
||||
// then transpose them to the right place.
|
||||
memcpy(&pose._11, &eyeToHead.m, sizeof(eyeToHead.m));
|
||||
pose.Transpose();
|
||||
pose.Invert();
|
||||
headToEyeTransforms[eye] = pose;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
OpenVRSession::GetSensorState(VRSystemState& state)
|
||||
{
|
||||
const uint32_t posesSize = ::vr::k_unTrackedDeviceIndex_Hmd + 1;
|
||||
::vr::TrackedDevicePose_t poses[posesSize];
|
||||
// Note: We *must* call WaitGetPoses in order for any rendering to happen at all.
|
||||
mVRCompositor->WaitGetPoses(nullptr, 0, poses, posesSize);
|
||||
gfx::Matrix4x4 headToEyeTransforms[2];
|
||||
UpdateEyeParameters(state.displayState, headToEyeTransforms);
|
||||
|
||||
::vr::Compositor_FrameTiming timing;
|
||||
timing.m_nSize = sizeof(::vr::Compositor_FrameTiming);
|
||||
if (mVRCompositor->GetFrameTiming(&timing)) {
|
||||
state.sensorState.timestamp = timing.m_flSystemTimeInSeconds;
|
||||
} else {
|
||||
// This should not happen, but log it just in case
|
||||
fprintf(stderr, "OpenVR - IVRCompositor::GetFrameTiming failed");
|
||||
}
|
||||
|
||||
if (poses[::vr::k_unTrackedDeviceIndex_Hmd].bDeviceIsConnected &&
|
||||
poses[::vr::k_unTrackedDeviceIndex_Hmd].bPoseIsValid &&
|
||||
poses[::vr::k_unTrackedDeviceIndex_Hmd].eTrackingResult == ::vr::TrackingResult_Running_OK)
|
||||
{
|
||||
const ::vr::TrackedDevicePose_t& pose = poses[::vr::k_unTrackedDeviceIndex_Hmd];
|
||||
|
||||
gfx::Matrix4x4 m;
|
||||
// NOTE! mDeviceToAbsoluteTracking is a 3x4 matrix, not 4x4. But
|
||||
// because of its arrangement, we can copy the 12 elements in and
|
||||
// then transpose them to the right place. We do this so we can
|
||||
// pull out a Quaternion.
|
||||
memcpy(&m._11, &pose.mDeviceToAbsoluteTracking, sizeof(pose.mDeviceToAbsoluteTracking));
|
||||
m.Transpose();
|
||||
|
||||
gfx::Quaternion rot;
|
||||
rot.SetFromRotationMatrix(m);
|
||||
rot.Invert();
|
||||
|
||||
state.sensorState.flags = (VRDisplayCapabilityFlags)((int)state.sensorState.flags | (int)VRDisplayCapabilityFlags::Cap_Orientation);
|
||||
state.sensorState.orientation[0] = rot.x;
|
||||
state.sensorState.orientation[1] = rot.y;
|
||||
state.sensorState.orientation[2] = rot.z;
|
||||
state.sensorState.orientation[3] = rot.w;
|
||||
state.sensorState.angularVelocity[0] = pose.vAngularVelocity.v[0];
|
||||
state.sensorState.angularVelocity[1] = pose.vAngularVelocity.v[1];
|
||||
state.sensorState.angularVelocity[2] = pose.vAngularVelocity.v[2];
|
||||
|
||||
state.sensorState.flags =(VRDisplayCapabilityFlags)((int)state.sensorState.flags | (int)VRDisplayCapabilityFlags::Cap_Position);
|
||||
state.sensorState.position[0] = m._41;
|
||||
state.sensorState.position[1] = m._42;
|
||||
state.sensorState.position[2] = m._43;
|
||||
state.sensorState.linearVelocity[0] = pose.vVelocity.v[0];
|
||||
state.sensorState.linearVelocity[1] = pose.vVelocity.v[1];
|
||||
state.sensorState.linearVelocity[2] = pose.vVelocity.v[2];
|
||||
}
|
||||
|
||||
state.sensorState.CalcViewMatrices(headToEyeTransforms);
|
||||
state.sensorState.inputFrameID++;
|
||||
}
|
||||
|
||||
void
|
||||
OpenVRSession::GetControllerState(VRSystemState &state)
|
||||
{
|
||||
// TODO - Implement
|
||||
}
|
||||
|
||||
void
|
||||
OpenVRSession::StartFrame(mozilla::gfx::VRSystemState& aSystemState)
|
||||
{
|
||||
GetSensorState(aSystemState);
|
||||
GetControllerState(aSystemState);
|
||||
}
|
||||
|
||||
bool
|
||||
OpenVRSession::ShouldQuit() const
|
||||
{
|
||||
return mShouldQuit;
|
||||
}
|
||||
|
||||
void
|
||||
OpenVRSession::ProcessEvents(mozilla::gfx::VRSystemState& aSystemState)
|
||||
{
|
||||
bool isHmdPresent = ::vr::VR_IsHmdPresent();
|
||||
if (!isHmdPresent) {
|
||||
mShouldQuit = true;
|
||||
}
|
||||
|
||||
::vr::VREvent_t event;
|
||||
while (mVRSystem && mVRSystem->PollNextEvent(&event, sizeof(event))) {
|
||||
switch (event.eventType) {
|
||||
case ::vr::VREvent_TrackedDeviceUserInteractionStarted:
|
||||
if (event.trackedDeviceIndex == ::vr::k_unTrackedDeviceIndex_Hmd) {
|
||||
aSystemState.displayState.mIsMounted = true;
|
||||
}
|
||||
break;
|
||||
case ::vr::VREvent_TrackedDeviceUserInteractionEnded:
|
||||
if (event.trackedDeviceIndex == ::vr::k_unTrackedDeviceIndex_Hmd) {
|
||||
aSystemState.displayState.mIsMounted = false;
|
||||
}
|
||||
break;
|
||||
case ::vr::EVREventType::VREvent_TrackedDeviceActivated:
|
||||
if (event.trackedDeviceIndex == ::vr::k_unTrackedDeviceIndex_Hmd) {
|
||||
aSystemState.displayState.mIsConnected = true;
|
||||
}
|
||||
break;
|
||||
case ::vr::EVREventType::VREvent_TrackedDeviceDeactivated:
|
||||
if (event.trackedDeviceIndex == ::vr::k_unTrackedDeviceIndex_Hmd) {
|
||||
aSystemState.displayState.mIsConnected = false;
|
||||
}
|
||||
break;
|
||||
case ::vr::EVREventType::VREvent_DriverRequestedQuit:
|
||||
case ::vr::EVREventType::VREvent_Quit:
|
||||
case ::vr::EVREventType::VREvent_ProcessQuit:
|
||||
case ::vr::EVREventType::VREvent_QuitAcknowledged:
|
||||
case ::vr::EVREventType::VREvent_QuitAborted_UserPrompt:
|
||||
mShouldQuit = true;
|
||||
break;
|
||||
default:
|
||||
// ignore
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
OpenVRSession::SubmitFrame(const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer)
|
||||
{
|
||||
#if defined(XP_WIN)
|
||||
|
||||
if (aLayer.mTextureType == VRLayerTextureType::LayerTextureType_D3D10SurfaceDescriptor) {
|
||||
RefPtr<ID3D11Texture2D> dxTexture;
|
||||
HRESULT hr = mDevice->OpenSharedResource((HANDLE)aLayer.mTextureHandle,
|
||||
__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<IDXGIKeyedMutex> 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((void *)dxTexture,
|
||||
::vr::ETextureType::TextureType_DirectX,
|
||||
aLayer.mLeftEyeRect, aLayer.mRightEyeRect);
|
||||
if (mutex) {
|
||||
HRESULT hr = mutex->ReleaseSync(0);
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Failed to unlock the texture");
|
||||
}
|
||||
}
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#elif defined(XP_MACOSX)
|
||||
|
||||
if (aLayer.mTextureType == VRLayerTextureType::LayerTextureType_MacIOSurface) {
|
||||
return SubmitFrame(aLayer.mTextureHandle,
|
||||
::vr::ETextureType::TextureType_IOSurface,
|
||||
aLayer.mLeftEyeRect, aLayer.mRightEyeRect);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
OpenVRSession::SubmitFrame(void* aTextureHandle,
|
||||
::vr::ETextureType aTextureType,
|
||||
const VRLayerEyeRect& aLeftEyeRect,
|
||||
const VRLayerEyeRect& aRightEyeRect)
|
||||
{
|
||||
::vr::Texture_t tex;
|
||||
tex.handle = aTextureHandle;
|
||||
tex.eType = aTextureType;
|
||||
tex.eColorSpace = ::vr::EColorSpace::ColorSpace_Auto;
|
||||
|
||||
::vr::VRTextureBounds_t bounds;
|
||||
bounds.uMin = aLeftEyeRect.x;
|
||||
bounds.vMin = 1.0 - aLeftEyeRect.y;
|
||||
bounds.uMax = aLeftEyeRect.x + aLeftEyeRect.width;
|
||||
bounds.vMax = 1.0 - (aLeftEyeRect.y + aLeftEyeRect.height);
|
||||
|
||||
::vr::EVRCompositorError err;
|
||||
err = mVRCompositor->Submit(::vr::EVREye::Eye_Left, &tex, &bounds);
|
||||
if (err != ::vr::EVRCompositorError::VRCompositorError_None) {
|
||||
printf_stderr("OpenVR Compositor Submit() failed.\n");
|
||||
}
|
||||
|
||||
bounds.uMin = aRightEyeRect.x;
|
||||
bounds.vMin = 1.0 - aRightEyeRect.y;
|
||||
bounds.uMax = aRightEyeRect.x + aRightEyeRect.width;
|
||||
bounds.vMax = 1.0 - (aRightEyeRect.y + aRightEyeRect.height);
|
||||
|
||||
err = mVRCompositor->Submit(::vr::EVREye::Eye_Right, &tex, &bounds);
|
||||
if (err != ::vr::EVRCompositorError::VRCompositorError_None) {
|
||||
printf_stderr("OpenVR Compositor Submit() failed.\n");
|
||||
}
|
||||
|
||||
mVRCompositor->PostPresentHandoff();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
OpenVRSession::StopPresentation()
|
||||
{
|
||||
mVRCompositor->ClearLastSubmittedFrame();
|
||||
|
||||
::vr::Compositor_CumulativeStats stats;
|
||||
mVRCompositor->GetCumulativeStats(&stats, sizeof(::vr::Compositor_CumulativeStats));
|
||||
// TODO - Need to send telemetry back to browser.
|
||||
// Bug 1473398 will refactor this original gfxVROpenVR code:
|
||||
// const uint32_t droppedFramesPerSec = (stats.m_nNumReprojectedFrames -
|
||||
// mTelemetry.mLastDroppedFrameCount) / duration.ToSeconds();
|
||||
// Telemetry::Accumulate(Telemetry::WEBVR_DROPPED_FRAMES_IN_OPENVR, droppedFramesPerSec);
|
||||
}
|
||||
|
||||
bool
|
||||
OpenVRSession::StartPresentation()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace gfx
|
|
@ -0,0 +1,65 @@
|
|||
/* -*- 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_SERVICE_OPENVRSESSION_H
|
||||
#define GFX_VR_SERVICE_OPENVRSESSION_H
|
||||
|
||||
#include "VRSession.h"
|
||||
|
||||
#include "openvr.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "moz_external_vr.h"
|
||||
|
||||
#if defined(XP_WIN)
|
||||
#include <d3d11_1.h>
|
||||
#elif defined(XP_MACOSX)
|
||||
class MacIOSurface;
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
class OpenVRSession : public VRSession
|
||||
{
|
||||
public:
|
||||
OpenVRSession();
|
||||
virtual ~OpenVRSession();
|
||||
|
||||
bool Initialize(mozilla::gfx::VRSystemState& aSystemState) override;
|
||||
void Shutdown() override;
|
||||
void ProcessEvents(mozilla::gfx::VRSystemState& aSystemState) override;
|
||||
void StartFrame(mozilla::gfx::VRSystemState& aSystemState) override;
|
||||
bool ShouldQuit() const override;
|
||||
bool StartPresentation() override;
|
||||
void StopPresentation() override;
|
||||
bool SubmitFrame(const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer) override;
|
||||
|
||||
private:
|
||||
// OpenVR State
|
||||
::vr::IVRSystem* mVRSystem = nullptr;
|
||||
::vr::IVRChaperone* mVRChaperone = nullptr;
|
||||
::vr::IVRCompositor* mVRCompositor = nullptr;
|
||||
bool mShouldQuit;
|
||||
|
||||
bool InitState(mozilla::gfx::VRSystemState& aSystemState);
|
||||
void UpdateStageParameters(mozilla::gfx::VRDisplayState& state);
|
||||
void UpdateEyeParameters(mozilla::gfx::VRDisplayState& state, gfx::Matrix4x4* headToEyeTransforms = nullptr);
|
||||
void GetSensorState(mozilla::gfx::VRSystemState& state);
|
||||
void GetControllerState(VRSystemState &state);
|
||||
|
||||
bool SubmitFrame(void* aTextureHandle,
|
||||
::vr::ETextureType aTextureType,
|
||||
const VRLayerEyeRect& aLeftEyeRect,
|
||||
const VRLayerEyeRect& aRightEyeRect);
|
||||
#if defined(XP_WIN)
|
||||
bool CreateD3DObjects();
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace gfx
|
||||
|
||||
#endif // GFX_VR_SERVICE_OPENVRSESSION_H
|
|
@ -0,0 +1,332 @@
|
|||
/* -*- 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 "VRService.h"
|
||||
#include "OpenVRSession.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "base/thread.h" // for Thread
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
|
||||
int64_t
|
||||
FrameIDFromBrowserState(const mozilla::gfx::VRBrowserState& aState)
|
||||
{
|
||||
for (int iLayer=0; iLayer < kVRLayerMaxCount; iLayer++) {
|
||||
const VRLayerState& layer = aState.layerState[iLayer];
|
||||
if (layer.type == VRLayerType::LayerType_Stereo_Immersive) {
|
||||
return layer.layer_stereo_immersive.mFrameId;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
IsImmersiveContentActive(const mozilla::gfx::VRBrowserState& aState)
|
||||
{
|
||||
for (int iLayer=0; iLayer < kVRLayerMaxCount; iLayer++) {
|
||||
const VRLayerState& layer = aState.layerState[iLayer];
|
||||
if (layer.type == VRLayerType::LayerType_Stereo_Immersive) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
/*static*/ already_AddRefed<VRService>
|
||||
VRService::Create()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!gfxPrefs::VRServiceEnabled()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<VRService> service = new VRService();
|
||||
return service.forget();
|
||||
}
|
||||
|
||||
VRService::VRService()
|
||||
: mSystemState{}
|
||||
, mBrowserState{}
|
||||
, mServiceThread(nullptr)
|
||||
, mShutdownRequested(false)
|
||||
{
|
||||
memset(&mAPIShmem, 0, sizeof(mAPIShmem));
|
||||
}
|
||||
|
||||
VRService::~VRService()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
void
|
||||
VRService::Start()
|
||||
{
|
||||
if (!mServiceThread) {
|
||||
/**
|
||||
* We must ensure that any time the service is re-started, that
|
||||
* the VRSystemState is reset, including mSystemState.enumerationCompleted
|
||||
* This must happen before VRService::Start returns to the caller, in order
|
||||
* to prevent the WebVR/WebXR promises from being resolved before the
|
||||
* enumeration has been completed.
|
||||
*/
|
||||
memset(&mSystemState, 0, sizeof(mSystemState));
|
||||
PushState(mSystemState);
|
||||
|
||||
mServiceThread = new base::Thread("VRService");
|
||||
base::Thread::Options options;
|
||||
/* Timeout values are powers-of-two to enable us get better data.
|
||||
128ms is chosen for transient hangs because 8Hz should be the minimally
|
||||
acceptable goal for Compositor responsiveness (normal goal is 60Hz). */
|
||||
options.transient_hang_timeout = 128; // milliseconds
|
||||
/* 2048ms is chosen for permanent hangs because it's longer than most
|
||||
* Compositor hangs seen in the wild, but is short enough to not miss getting
|
||||
* native hang stacks. */
|
||||
options.permanent_hang_timeout = 2048; // milliseconds
|
||||
|
||||
if (!mServiceThread->StartWithOptions(options)) {
|
||||
delete mServiceThread;
|
||||
mServiceThread = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
mServiceThread->message_loop()->PostTask(NewRunnableMethod(
|
||||
"gfx::VRService::ServiceInitialize",
|
||||
this, &VRService::ServiceInitialize
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VRService::Stop()
|
||||
{
|
||||
if (mServiceThread) {
|
||||
mServiceThread->message_loop()->PostTask(NewRunnableMethod(
|
||||
"gfx::VRService::RequestShutdown",
|
||||
this, &VRService::RequestShutdown
|
||||
));
|
||||
delete mServiceThread;
|
||||
mServiceThread = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
VRService::IsInServiceThread()
|
||||
{
|
||||
return mServiceThread && mServiceThread->thread_id() == PlatformThread::CurrentId();
|
||||
}
|
||||
|
||||
void
|
||||
VRService::RequestShutdown()
|
||||
{
|
||||
MOZ_ASSERT(IsInServiceThread());
|
||||
mShutdownRequested = true;
|
||||
}
|
||||
|
||||
void
|
||||
VRService::ServiceInitialize()
|
||||
{
|
||||
MOZ_ASSERT(IsInServiceThread());
|
||||
|
||||
mShutdownRequested = false;
|
||||
memset(&mBrowserState, 0, sizeof(mBrowserState));
|
||||
|
||||
// Try to start a VRSession
|
||||
unique_ptr<VRSession> session;
|
||||
|
||||
// Try OpenVR
|
||||
session = make_unique<OpenVRSession>();
|
||||
if (!session->Initialize(mSystemState)) {
|
||||
session = nullptr;
|
||||
}
|
||||
if (session) {
|
||||
mSession = std::move(session);
|
||||
// Setting enumerationCompleted to true indicates to the browser
|
||||
// that it should resolve any promises in the WebVR/WebXR API
|
||||
// waiting for hardware detection.
|
||||
mSystemState.enumerationCompleted = true;
|
||||
PushState(mSystemState);
|
||||
|
||||
MessageLoop::current()->PostTask(NewRunnableMethod(
|
||||
"gfx::VRService::ServiceWaitForImmersive",
|
||||
this, &VRService::ServiceWaitForImmersive
|
||||
));
|
||||
} else {
|
||||
// VR hardware was not detected.
|
||||
// We must inform the browser of the failure so it may try again
|
||||
// later and resolve WebVR promises. A failure or shutdown is
|
||||
// indicated by enumerationCompleted being set to true, with all
|
||||
// other fields remaining zeroed out.
|
||||
memset(&mSystemState, 0, sizeof(mSystemState));
|
||||
mSystemState.enumerationCompleted = true;
|
||||
PushState(mSystemState);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VRService::ServiceShutdown()
|
||||
{
|
||||
MOZ_ASSERT(IsInServiceThread());
|
||||
|
||||
mSession = nullptr;
|
||||
|
||||
// Notify the browser that we have shut down.
|
||||
// This is indicated by enumerationCompleted being set
|
||||
// to true, with all other fields remaining zeroed out.
|
||||
memset(&mSystemState, 0, sizeof(mSystemState));
|
||||
mSystemState.enumerationCompleted = true;
|
||||
PushState(mSystemState);
|
||||
}
|
||||
|
||||
void
|
||||
VRService::ServiceWaitForImmersive()
|
||||
{
|
||||
MOZ_ASSERT(IsInServiceThread());
|
||||
MOZ_ASSERT(mSession);
|
||||
|
||||
mSession->ProcessEvents(mSystemState);
|
||||
PushState(mSystemState);
|
||||
PullState(mBrowserState);
|
||||
|
||||
if (mSession->ShouldQuit() || mShutdownRequested) {
|
||||
// Shut down
|
||||
MessageLoop::current()->PostTask(NewRunnableMethod(
|
||||
"gfx::VRService::ServiceShutdown",
|
||||
this, &VRService::ServiceShutdown
|
||||
));
|
||||
} else if (IsImmersiveContentActive(mBrowserState)) {
|
||||
// Enter Immersive Mode
|
||||
mSession->StartPresentation();
|
||||
mSession->StartFrame(mSystemState);
|
||||
PushState(mSystemState);
|
||||
|
||||
MessageLoop::current()->PostTask(NewRunnableMethod(
|
||||
"gfx::VRService::ServiceImmersiveMode",
|
||||
this, &VRService::ServiceImmersiveMode
|
||||
));
|
||||
} else {
|
||||
// Continue waiting for immersive mode
|
||||
MessageLoop::current()->PostTask(NewRunnableMethod(
|
||||
"gfx::VRService::ServiceWaitForImmersive",
|
||||
this, &VRService::ServiceWaitForImmersive
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VRService::ServiceImmersiveMode()
|
||||
{
|
||||
MOZ_ASSERT(IsInServiceThread());
|
||||
MOZ_ASSERT(mSession);
|
||||
|
||||
mSession->ProcessEvents(mSystemState);
|
||||
PushState(mSystemState);
|
||||
PullState(mBrowserState);
|
||||
|
||||
if (mSession->ShouldQuit() || mShutdownRequested) {
|
||||
// Shut down
|
||||
MessageLoop::current()->PostTask(NewRunnableMethod(
|
||||
"gfx::VRService::ServiceShutdown",
|
||||
this, &VRService::ServiceShutdown
|
||||
));
|
||||
return;
|
||||
} else if (!IsImmersiveContentActive(mBrowserState)) {
|
||||
// Exit immersive mode
|
||||
mSession->StopPresentation();
|
||||
MessageLoop::current()->PostTask(NewRunnableMethod(
|
||||
"gfx::VRService::ServiceWaitForImmersive",
|
||||
this, &VRService::ServiceWaitForImmersive
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t newFrameId = FrameIDFromBrowserState(mBrowserState);
|
||||
if (newFrameId != mSystemState.displayState.mLastSubmittedFrameId) {
|
||||
// A new immersive frame has been received.
|
||||
// Submit the textures to the VR system compositor.
|
||||
bool success = false;
|
||||
for (int iLayer=0; iLayer < kVRLayerMaxCount; iLayer++) {
|
||||
const VRLayerState& layer = mBrowserState.layerState[iLayer];
|
||||
if (layer.type == VRLayerType::LayerType_Stereo_Immersive) {
|
||||
success = mSession->SubmitFrame(layer.layer_stereo_immersive);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Changing mLastSubmittedFrameId triggers a new frame to start
|
||||
// rendering. Changes to mLastSubmittedFrameId and the values
|
||||
// used for rendering, such as headset pose, must be pushed
|
||||
// atomically to the browser.
|
||||
mSystemState.displayState.mLastSubmittedFrameId = newFrameId;
|
||||
mSystemState.displayState.mLastSubmittedFrameSuccessful = success;
|
||||
mSession->StartFrame(mSystemState);
|
||||
PushState(mSystemState);
|
||||
}
|
||||
|
||||
// Continue immersive mode
|
||||
MessageLoop::current()->PostTask(NewRunnableMethod(
|
||||
"gfx::VRService::ServiceImmersiveMode",
|
||||
this, &VRService::ServiceImmersiveMode
|
||||
));
|
||||
}
|
||||
|
||||
void
|
||||
VRService::PushState(const mozilla::gfx::VRSystemState& aState)
|
||||
{
|
||||
// Copying the VR service state to the shmem is atomic, infallable,
|
||||
// and non-blocking on x86/x64 architectures. Arm requires a mutex
|
||||
// that is locked for the duration of the memcpy to and from shmem on
|
||||
// both sides.
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->systemMutex)) == 0) {
|
||||
memcpy((void *)&mAPIShmem.state, &aState, sizeof(VRSystemState));
|
||||
pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->systemMutex));
|
||||
}
|
||||
#else
|
||||
mAPIShmem.generationA++;
|
||||
memcpy((void *)&mAPIShmem.state, &aState, sizeof(VRSystemState));
|
||||
mAPIShmem.generationB++;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
VRService::PullState(mozilla::gfx::VRBrowserState& aState)
|
||||
{
|
||||
// Copying the browser state from the shmem is non-blocking
|
||||
// on x86/x64 architectures. Arm requires a mutex that is
|
||||
// locked for the duration of the memcpy to and from shmem on
|
||||
// both sides.
|
||||
// On x86/x64 It is fallable -- If a dirty copy is detected by
|
||||
// a mismatch of browserGenerationA and browserGenerationB,
|
||||
// the copy is discarded and will not replace the last known
|
||||
// browser state.
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->browserMutex)) == 0) {
|
||||
memcpy(&aState, &tmp.browserState, sizeof(VRBrowserState));
|
||||
pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->browserMutex));
|
||||
}
|
||||
#else
|
||||
VRExternalShmem tmp;
|
||||
memcpy(&tmp, &mAPIShmem, sizeof(VRExternalShmem));
|
||||
if (tmp.browserGenerationA == tmp.browserGenerationB && tmp.browserGenerationA != 0 && tmp.browserGenerationA != -1) {
|
||||
memcpy(&aState, &tmp.browserState, sizeof(VRBrowserState));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
VRExternalShmem*
|
||||
VRService::GetAPIShmem()
|
||||
{
|
||||
return &mAPIShmem;
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/* -*- 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_SERVICE_VRSERVICE_H
|
||||
#define GFX_VR_SERVICE_VRSERVICE_H
|
||||
|
||||
#include "mozilla/Atomics.h"
|
||||
|
||||
#include "moz_external_vr.h"
|
||||
|
||||
#include <thread>
|
||||
namespace base {
|
||||
class Thread;
|
||||
} // namespace base
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
class VRSession;
|
||||
|
||||
class VRService
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRService)
|
||||
static already_AddRefed<VRService> Create();
|
||||
|
||||
void Start();
|
||||
void Stop();
|
||||
VRExternalShmem* GetAPIShmem();
|
||||
|
||||
private:
|
||||
VRService();
|
||||
~VRService();
|
||||
void PushState(const mozilla::gfx::VRSystemState& aState);
|
||||
void PullState(mozilla::gfx::VRBrowserState& aState);
|
||||
|
||||
/**
|
||||
* VRSystemState contains the most recent state of the VR
|
||||
* system, to be shared with the browser by Shmem.
|
||||
* mSystemState is the VR Service copy of this data, which
|
||||
* is memcpy'ed atomically to the Shmem.
|
||||
* VRSystemState is written by the VR Service, but read-only
|
||||
* by the browser.
|
||||
*/
|
||||
VRSystemState mSystemState;
|
||||
/**
|
||||
* VRBrowserState contains the most recent state of the browser.
|
||||
* mBrowserState is memcpy'ed from the Shmem atomically
|
||||
*/
|
||||
VRBrowserState mBrowserState;
|
||||
|
||||
std::unique_ptr<VRSession> mSession;
|
||||
base::Thread* mServiceThread;
|
||||
bool mShutdownRequested;
|
||||
|
||||
VRExternalShmem mAPIShmem;
|
||||
|
||||
bool IsInServiceThread();
|
||||
void RequestShutdown();
|
||||
|
||||
/**
|
||||
* The VR Service thread is a state machine that always has one
|
||||
* task queued depending on the state.
|
||||
*
|
||||
* VR Service thread state task functions:
|
||||
*/
|
||||
void ServiceInitialize();
|
||||
void ServiceShutdown();
|
||||
void ServiceWaitForImmersive();
|
||||
void ServiceImmersiveMode();
|
||||
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // GFX_VR_SERVICE_VRSERVICE_H
|
|
@ -0,0 +1,80 @@
|
|||
#include "VRSession.h"
|
||||
|
||||
#include "moz_external_vr.h"
|
||||
|
||||
#if defined(XP_WIN)
|
||||
#include <d3d11.h>
|
||||
#endif // defined(XP_WIN)
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
VRSession::VRSession()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
VRSession::~VRSession()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#if defined(XP_WIN)
|
||||
bool
|
||||
VRSession::CreateD3DContext(RefPtr<ID3D11Device> aDevice)
|
||||
{
|
||||
if (!mDevice) {
|
||||
if (!aDevice) {
|
||||
NS_WARNING("OpenVRSession::CreateD3DObjects failed to get a D3D11Device");
|
||||
return false;
|
||||
}
|
||||
if (FAILED(aDevice->QueryInterface(__uuidof(ID3D11Device1), getter_AddRefs(mDevice)))) {
|
||||
NS_WARNING("OpenVRSession::CreateD3DObjects failed to get a D3D11Device1");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!mContext) {
|
||||
mDevice->GetImmediateContext1(getter_AddRefs(mContext));
|
||||
if (!mContext) {
|
||||
NS_WARNING("OpenVRSession::CreateD3DObjects failed to get an immediate context");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!mDeviceContextState) {
|
||||
D3D_FEATURE_LEVEL featureLevels[] {
|
||||
D3D_FEATURE_LEVEL_11_1,
|
||||
D3D_FEATURE_LEVEL_11_0
|
||||
};
|
||||
mDevice->CreateDeviceContextState(0,
|
||||
featureLevels,
|
||||
2,
|
||||
D3D11_SDK_VERSION,
|
||||
__uuidof(ID3D11Device1),
|
||||
nullptr,
|
||||
getter_AddRefs(mDeviceContextState));
|
||||
}
|
||||
if (!mDeviceContextState) {
|
||||
NS_WARNING("VRDisplayHost::CreateD3DObjects failed to get a D3D11DeviceContextState");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ID3D11Device1*
|
||||
VRSession::GetD3DDevice()
|
||||
{
|
||||
return mDevice;
|
||||
}
|
||||
|
||||
ID3D11DeviceContext1*
|
||||
VRSession::GetD3DDeviceContext()
|
||||
{
|
||||
return mContext;
|
||||
}
|
||||
|
||||
ID3DDeviceContextState*
|
||||
VRSession::GetD3DDeviceContextState()
|
||||
{
|
||||
return mDeviceContextState;
|
||||
}
|
||||
|
||||
#endif // defined(XP_WIN)
|
|
@ -0,0 +1,53 @@
|
|||
/* -*- 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_SERVICE_VRSESSION_H
|
||||
#define GFX_VR_SERVICE_VRSESSION_H
|
||||
|
||||
#include "VRSession.h"
|
||||
|
||||
#include "moz_external_vr.h"
|
||||
|
||||
#if defined(XP_WIN)
|
||||
#include <d3d11_1.h>
|
||||
#elif defined(XP_MACOSX)
|
||||
class MacIOSurface;
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
class VRSession
|
||||
{
|
||||
public:
|
||||
VRSession();
|
||||
virtual ~VRSession();
|
||||
|
||||
virtual bool Initialize(mozilla::gfx::VRSystemState& aSystemState) = 0;
|
||||
virtual void Shutdown() = 0;
|
||||
virtual void ProcessEvents(mozilla::gfx::VRSystemState& aSystemState) = 0;
|
||||
virtual void StartFrame(mozilla::gfx::VRSystemState& aSystemState) = 0;
|
||||
virtual bool ShouldQuit() const = 0;
|
||||
virtual bool StartPresentation() = 0;
|
||||
virtual void StopPresentation() = 0;
|
||||
virtual bool SubmitFrame(const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer) = 0;
|
||||
|
||||
#if defined(XP_WIN)
|
||||
protected:
|
||||
bool CreateD3DContext(RefPtr<ID3D11Device> aDevice);
|
||||
RefPtr<ID3D11Device1> mDevice;
|
||||
RefPtr<ID3D11DeviceContext1> mContext;
|
||||
ID3D11Device1* GetD3DDevice();
|
||||
ID3D11DeviceContext1* GetD3DDeviceContext();
|
||||
ID3DDeviceContextState* GetD3DDeviceContextState();
|
||||
RefPtr<ID3DDeviceContextState> mDeviceContextState;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace gfx
|
||||
|
||||
#endif // GFX_VR_SERVICE_VRSESSION_H
|
|
@ -0,0 +1,21 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
# Build OpenVR on Windows, Linux, and macOS desktop targets
|
||||
if CONFIG['OS_TARGET'] in ('WINNT', 'Linux', 'Darwin'):
|
||||
UNIFIED_SOURCES += [
|
||||
'OpenVRSession.cpp',
|
||||
'VRService.cpp',
|
||||
'VRSession.cpp',
|
||||
]
|
||||
LOCAL_INCLUDES += [
|
||||
'/dom/base',
|
||||
'/gfx/layers/d3d11',
|
||||
'/gfx/thebes',
|
||||
]
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
|
@ -5283,6 +5283,8 @@ pref("dom.vr.puppet.submitframe", 0);
|
|||
pref("dom.vr.display.rafMaxDuration", 50);
|
||||
// VR test system.
|
||||
pref("dom.vr.test.enabled", false);
|
||||
// Enable the VR Service, which interfaces with VR hardware in a separate thread
|
||||
pref("dom.vr.service.enabled", false);
|
||||
|
||||
// If the user puts a finger down on an element and we think the user
|
||||
// might be executing a pan gesture, how long do we wait before
|
||||
|
|
Загрузка…
Ссылка в новой задаче