diff options
Diffstat (limited to 'gfx/vr/service/VRSession.cpp')
-rw-r--r-- | gfx/vr/service/VRSession.cpp | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/gfx/vr/service/VRSession.cpp b/gfx/vr/service/VRSession.cpp new file mode 100644 index 0000000000..44f9fb14bc --- /dev/null +++ b/gfx/vr/service/VRSession.cpp @@ -0,0 +1,196 @@ +/* -*- 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 "VRSession.h" + +#include "moz_external_vr.h" + +#if defined(XP_WIN) +# include <d3d11.h> +#endif // defined(XP_WIN) + +#if defined(MOZILLA_INTERNAL_API) +# if defined(XP_WIN) +# include "mozilla/gfx/Logging.h" +# endif +#else +# define NS_WARNING(s) +#endif + +using namespace mozilla::gfx; + +VRSession::VRSession() + : mShouldQuit(false) +#ifdef XP_WIN + , + mDevice(nullptr), + mContext(nullptr), + mDeviceContextState(nullptr) +#endif +{ +} + +#ifdef XP_WIN +VRSession::~VRSession() { + if (mDevice != nullptr) { + mDevice->Release(); + mDevice = nullptr; + } + + if (mContext != nullptr) { + mContext->Release(); + mContext = nullptr; + } + + if (mDeviceContextState != nullptr) { + mDeviceContextState->Release(); + mDeviceContextState = nullptr; + } +} +#endif + +#if defined(XP_WIN) +bool VRSession::CreateD3DContext(ID3D11Device* aDevice) { + if (!mDevice) { + if (!aDevice) { + NS_WARNING("VRSession::CreateD3DObjects failed to get a D3D11Device"); + return false; + } + if (FAILED(aDevice->QueryInterface(IID_PPV_ARGS(&mDevice)))) { + NS_WARNING("VRSession::CreateD3DObjects failed to get a D3D11Device1"); + return false; + } + } + if (!mContext) { + mDevice->GetImmediateContext1(&mContext); + if (!mContext) { + NS_WARNING( + "VRSession::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, + &mDeviceContextState); + } + if (!mDeviceContextState) { + NS_WARNING( + "VRSession::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) + +bool VRSession::SubmitFrame( + const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer) { +#if defined(XP_WIN) + bool success = false; + if (aLayer.textureType == + VRLayerTextureType::LayerTextureType_D3D10SurfaceDescriptor) { + ID3D11Texture2D* dxTexture = nullptr; + HRESULT hr = mDevice->OpenSharedResource((HANDLE)aLayer.textureHandle, + IID_PPV_ARGS(&dxTexture)); + if (SUCCEEDED(hr) && dxTexture != nullptr) { + // Similar to LockD3DTexture in TextureD3D11.cpp + IDXGIKeyedMutex* mutex = nullptr; + hr = dxTexture->QueryInterface(IID_PPV_ARGS(&mutex)); + if (SUCCEEDED(hr)) { + hr = mutex->AcquireSync(0, 1000); +# ifdef MOZILLA_INTERNAL_API + if (hr == WAIT_TIMEOUT) { + gfxDevCrash(LogReason::D3DLockTimeout) << "D3D lock mutex timeout"; + } else if (hr == WAIT_ABANDONED) { + gfxCriticalNote << "GFX: D3D11 lock mutex abandoned"; + } +# endif + if (SUCCEEDED(hr)) { + success = SubmitFrame(aLayer, dxTexture); + hr = mutex->ReleaseSync(0); + if (FAILED(hr)) { + NS_WARNING("Failed to unlock the texture"); + } + } else { + NS_WARNING("Failed to lock the texture"); + } + + mutex->Release(); + mutex = nullptr; + } + + dxTexture->Release(); + dxTexture = nullptr; + } else { + NS_WARNING("Failed to open shared texture"); + } + + return SUCCEEDED(hr) && success; + } + +#elif defined(XP_MACOSX) + + if (aLayer.textureType == VRLayerTextureType::LayerTextureType_MacIOSurface) { + return SubmitFrame(aLayer, aLayer.textureHandle); + } + +#endif + + return false; +} + +void VRSession::UpdateTrigger(VRControllerState& aState, uint32_t aButtonIndex, + float aValue, float aThreshold) { + // For OpenVR, the threshold value of ButtonPressed and ButtonTouched is 0.55. + // We prefer to let developers to set their own threshold for the adjustment. + // Therefore, we don't check ButtonPressed and ButtonTouched with ButtonMask + // here. we just check the button value is larger than the threshold value or + // not. + uint64_t mask = (1ULL << aButtonIndex); + aState.triggerValue[aButtonIndex] = aValue; + if (aValue > aThreshold) { + aState.buttonPressed |= mask; + aState.buttonTouched |= mask; + } else { + aState.buttonPressed &= ~mask; + aState.buttonTouched &= ~mask; + } +} + +void VRSession::SetControllerSelectionAndSqueezeFrameId( + VRControllerState& controllerState, uint64_t aFrameId) { + // The 1st button, trigger, is its selection action. + const bool selectionPressed = controllerState.buttonPressed & 1ULL; + if (selectionPressed && controllerState.selectActionStopFrameId >= + controllerState.selectActionStartFrameId) { + controllerState.selectActionStartFrameId = aFrameId; + } else if (!selectionPressed && controllerState.selectActionStartFrameId > + controllerState.selectActionStopFrameId) { + controllerState.selectActionStopFrameId = aFrameId; + } + // The 2nd button, squeeze, is its squeeze action. + const bool squeezePressed = controllerState.buttonPressed & (1ULL << 1); + if (squeezePressed && controllerState.squeezeActionStopFrameId >= + controllerState.squeezeActionStartFrameId) { + controllerState.squeezeActionStartFrameId = aFrameId; + } else if (!squeezePressed && controllerState.squeezeActionStartFrameId > + controllerState.squeezeActionStopFrameId) { + controllerState.squeezeActionStopFrameId = aFrameId; + } +} + +bool VRSession::ShouldQuit() const { return mShouldQuit; } |