/* -*- 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 #include "prlink.h" #include "prenv.h" #include "gfxPrefs.h" #include "mozilla/Preferences.h" #include "mozilla/gfx/Quaternion.h" #ifdef XP_WIN #include "CompositorD3D11.h" #include "TextureD3D11.h" static const char* kShmemName = "moz.gecko.vr_ext.0.0.1"; #elif defined(XP_MACOSX) #include "mozilla/gfx/MacIOSurface.h" #include #include /* For mode constants */ #include /* For O_* constants */ #include static const char* kShmemName = "/moz.gecko.vr_ext.0.0.1"; #endif #include "gfxVRExternal.h" #include "VRManagerParent.h" #include "VRManager.h" #include "VRThread.h" #include "nsServiceManagerUtils.h" #include "nsIScreenManager.h" #include "mozilla/dom/GamepadEventTypes.h" #include "mozilla/dom/GamepadBinding.h" #include "mozilla/Telemetry.h" #ifndef M_PI # define M_PI 3.14159265358979323846 #endif using namespace mozilla; using namespace mozilla::gfx; using namespace mozilla::gfx::impl; using namespace mozilla::layers; using namespace mozilla::dom; static const uint32_t kNumExternalHaptcs = 1; VRDisplayExternal::VRDisplayExternal(const VRDisplayState& aDisplayState) : VRDisplayHost(VRDeviceType::External) , mIsPresenting(false) , mLastSensorState{} { MOZ_COUNT_CTOR_INHERITED(VRDisplayExternal, VRDisplayHost); mDisplayInfo.mDisplayState = aDisplayState; // default to an identity quaternion mLastSensorState.orientation[3] = 1.0f; } VRDisplayExternal::~VRDisplayExternal() { Destroy(); MOZ_COUNT_DTOR_INHERITED(VRDisplayExternal, VRDisplayHost); } void VRDisplayExternal::Destroy() { StopPresentation(); // TODO - Implement } void VRDisplayExternal::ZeroSensor() { } void VRDisplayExternal::Refresh() { VRManager *vm = VRManager::Get(); VRSystemManagerExternal* manager = vm->GetExternalManager(); manager->PullState(&mDisplayInfo.mDisplayState); } VRHMDSensorState VRDisplayExternal::GetSensorState() { VRManager *vm = VRManager::Get(); VRSystemManagerExternal* manager = vm->GetExternalManager(); manager->PullState(&mDisplayInfo.mDisplayState, &mLastSensorState); // result.CalcViewMatrices(headToEyeTransforms); mLastSensorState.inputFrameID = mDisplayInfo.mFrameId; return mLastSensorState; } void VRDisplayExternal::StartPresentation() { if (mIsPresenting) { return; } mIsPresenting = true; mTelemetry.Clear(); mTelemetry.mPresentationStart = TimeStamp::Now(); // TODO - Implement this // mTelemetry.mLastDroppedFrameCount = stats.m_nNumReprojectedFrames; } void VRDisplayExternal::StopPresentation() { if (!mIsPresenting) { return; } // TODO - Implement this /* mIsPresenting = false; const TimeDuration duration = TimeStamp::Now() - mTelemetry.mPresentationStart; Telemetry::Accumulate(Telemetry::WEBVR_USERS_VIEW_IN, 2); Telemetry::Accumulate(Telemetry::WEBVR_TIME_SPENT_VIEWING_IN_OPENVR, duration.ToMilliseconds()); ::vr::Compositor_CumulativeStats stats; mVRCompositor->GetCumulativeStats(&stats, sizeof(::vr::Compositor_CumulativeStats)); const uint32_t droppedFramesPerSec = (stats.m_nNumReprojectedFrames - mTelemetry.mLastDroppedFrameCount) / duration.ToSeconds(); Telemetry::Accumulate(Telemetry::WEBVR_DROPPED_FRAMES_IN_OPENVR, droppedFramesPerSec); */ } #if defined(XP_WIN) bool VRDisplayExternal::SubmitFrame(ID3D11Texture2D* aSource, const IntSize& aSize, const gfx::Rect& aLeftEyeRect, const gfx::Rect& aRightEyeRect) { // FINDME! Implement this return false; } #elif defined(XP_MACOSX) bool VRDisplayExternal::SubmitFrame(MacIOSurface* aMacIOSurface, const IntSize& aSize, const gfx::Rect& aLeftEyeRect, const gfx::Rect& aRightEyeRect) { const void* ioSurface = aMacIOSurface->GetIOSurfacePtr(); bool result = false; if (ioSurface == nullptr) { NS_WARNING("VRDisplayExternal::SubmitFrame() could not get an IOSurface"); } else { // FINDME! Implement this } return result; } #endif VRControllerExternal::VRControllerExternal(dom::GamepadHand aHand, uint32_t aDisplayID, uint32_t aNumButtons, uint32_t aNumTriggers, uint32_t aNumAxes, const nsCString& aId) : VRControllerHost(VRDeviceType::External, aHand, aDisplayID) { MOZ_COUNT_CTOR_INHERITED(VRControllerExternal, VRControllerHost); VRControllerState& state = mControllerInfo.mControllerState; strncpy(state.mControllerName, aId.BeginReading(), kVRControllerNameMaxLen); state.mNumButtons = aNumButtons; state.mNumAxes = aNumAxes; state.mNumTriggers = aNumTriggers; state.mNumHaptics = kNumExternalHaptcs; } VRControllerExternal::~VRControllerExternal() { MOZ_COUNT_DTOR_INHERITED(VRControllerExternal, VRControllerHost); } VRSystemManagerExternal::VRSystemManagerExternal() : mExternalShmem(nullptr) { #if defined(XP_MACOSX) mShmemFD = 0; #elif defined(XP_WIN) mShmemFile = NULL; #endif } VRSystemManagerExternal::~VRSystemManagerExternal() { CloseShmem(); } void VRSystemManagerExternal::OpenShmem() { if (mExternalShmem) { return; } #if defined(XP_MACOSX) if (mShmemFD == 0) { mShmemFD = shm_open(kShmemName, O_RDWR, S_IRUSR | S_IWUSR | S_IROTH | S_IWOTH); } if (mShmemFD <= 0) { mShmemFD = 0; return; } struct stat sb; fstat(mShmemFD, &sb); off_t length = sb.st_size; if (length < (off_t)sizeof(VRExternalShmem)) { // TODO - Implement logging CloseShmem(); return; } mExternalShmem = (VRExternalShmem*)mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_SHARED, mShmemFD, 0); if (mExternalShmem == MAP_FAILED) { // TODO - Implement logging mExternalShmem = NULL; CloseShmem(); return; } #elif defined(XP_WIN) if (mShmemFile == NULL) { mShmemFile = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, kShmemName); if (mShmemFile == NULL) { // TODO - Implement logging CloseShmem(); return; } } LARGE_INTEGER length; length.QuadPart = sizeof(VRExternalShmem); mExternalShmem = (VRExternalShmem*)MapViewOfFile(mShmemFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, length.QuadPart); if (mExternalShmem == NULL) { // TODO - Implement logging CloseShmem(); return; } #endif CheckForShutdown(); } void VRSystemManagerExternal::CheckForShutdown() { if (mExternalShmem) { if (mExternalShmem->generationA == -1 && mExternalShmem->generationB == -1) { Shutdown(); } } } void VRSystemManagerExternal::CloseShmem() { #if defined(XP_MACOSX) if (mExternalShmem) { munmap((void *)mExternalShmem, sizeof(VRExternalShmem)); mExternalShmem = NULL; } if (mShmemFD) { close(mShmemFD); } mShmemFD = 0; #elif defined(XP_WIN) if (mExternalShmem) { UnmapViewOfFile((void *)mExternalShmem); mExternalShmem = NULL; } if (mShmemFile) { CloseHandle(mShmemFile); mShmemFile = NULL; } #endif } /*static*/ already_AddRefed VRSystemManagerExternal::Create() { MOZ_ASSERT(NS_IsMainThread()); if (!gfxPrefs::VREnabled() || !gfxPrefs::VRExternalEnabled()) { return nullptr; } RefPtr manager = new VRSystemManagerExternal(); return manager.forget(); } void VRSystemManagerExternal::Destroy() { Shutdown(); } void VRSystemManagerExternal::Shutdown() { if (mDisplay) { mDisplay = nullptr; } RemoveControllers(); CloseShmem(); } void VRSystemManagerExternal::NotifyVSync() { VRSystemManager::NotifyVSync(); CheckForShutdown(); if (mDisplay) { mDisplay->Refresh(); } } void VRSystemManagerExternal::Enumerate() { if (mDisplay == nullptr) { OpenShmem(); if (mExternalShmem) { VRDisplayState displayState; PullState(&displayState); if (displayState.mIsConnected) { mDisplay = new VRDisplayExternal(displayState); } } } } bool VRSystemManagerExternal::ShouldInhibitEnumeration() { if (VRSystemManager::ShouldInhibitEnumeration()) { return true; } if (mDisplay) { // When we find an a VR device, don't // allow any further enumeration as it // may get picked up redundantly by other // API's. return true; } return false; } void VRSystemManagerExternal::GetHMDs(nsTArray>& aHMDResult) { if (mDisplay) { aHMDResult.AppendElement(mDisplay); } } bool VRSystemManagerExternal::GetIsPresenting() { if (mDisplay) { VRDisplayInfo displayInfo(mDisplay->GetDisplayInfo()); return displayInfo.GetPresentingGroups() != 0; } return false; } void VRSystemManagerExternal::HandleInput() { // TODO - Implement This! } void VRSystemManagerExternal::VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex, double aIntensity, double aDuration, const VRManagerPromise& aPromise) { // TODO - Implement this } void VRSystemManagerExternal::StopVibrateHaptic(uint32_t aControllerIdx) { // TODO - Implement this } void VRSystemManagerExternal::GetControllers(nsTArray>& aControllerResult) { aControllerResult.Clear(); for (uint32_t i = 0; i < mExternalController.Length(); ++i) { aControllerResult.AppendElement(mExternalController[i]); } } void VRSystemManagerExternal::ScanForControllers() { // TODO - Implement this } void VRSystemManagerExternal::RemoveControllers() { // The controller count is changed, removing the existing gamepads first. for (uint32_t i = 0; i < mExternalController.Length(); ++i) { RemoveGamepad(i); } mExternalController.Clear(); mControllerCount = 0; } void VRSystemManagerExternal::PullState(VRDisplayState* aDisplayState, VRHMDSensorState* aSensorState /* = nullptr */) { MOZ_ASSERT(mExternalShmem); if (mExternalShmem) { // TODO - Add locking here for non-x86 platforms VRExternalShmem tmp; memcpy(&tmp, (void *)mExternalShmem, sizeof(VRExternalShmem)); if (tmp.generationA == tmp.generationB && tmp.generationA != 0 && tmp.generationA != -1) { memcpy(aDisplayState, &tmp.state.displayState, sizeof(VRDisplayState)); if (aSensorState) { memcpy(aSensorState, &tmp.state.sensorState, sizeof(VRHMDSensorState)); } } } }