VRSession.cpp (6293B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "VRSession.h" 8 9 #include "moz_external_vr.h" 10 11 #include "mozilla/ipc/FileDescriptor.h" 12 13 #if defined(XP_WIN) 14 # include <d3d11.h> 15 #endif // defined(XP_WIN) 16 17 #if defined(MOZILLA_INTERNAL_API) 18 # if defined(XP_WIN) 19 # include "mozilla/gfx/Logging.h" 20 # endif 21 #else 22 # define NS_WARNING(s) 23 #endif 24 25 using namespace mozilla::gfx; 26 27 VRSession::VRSession() 28 : mShouldQuit(false) 29 #ifdef XP_WIN 30 , 31 mDevice(nullptr), 32 mContext(nullptr), 33 mDeviceContextState(nullptr) 34 #endif 35 { 36 } 37 38 #ifdef XP_WIN 39 VRSession::~VRSession() { 40 if (mDevice != nullptr) { 41 mDevice->Release(); 42 mDevice = nullptr; 43 } 44 45 if (mContext != nullptr) { 46 mContext->Release(); 47 mContext = nullptr; 48 } 49 50 if (mDeviceContextState != nullptr) { 51 mDeviceContextState->Release(); 52 mDeviceContextState = nullptr; 53 } 54 } 55 #endif 56 57 #if defined(XP_WIN) 58 bool VRSession::CreateD3DContext(ID3D11Device* aDevice) { 59 if (!mDevice) { 60 if (!aDevice) { 61 NS_WARNING("VRSession::CreateD3DObjects failed to get a D3D11Device"); 62 return false; 63 } 64 if (FAILED(aDevice->QueryInterface(IID_PPV_ARGS(&mDevice)))) { 65 NS_WARNING("VRSession::CreateD3DObjects failed to get a D3D11Device1"); 66 return false; 67 } 68 } 69 if (!mContext) { 70 mDevice->GetImmediateContext1(&mContext); 71 if (!mContext) { 72 NS_WARNING( 73 "VRSession::CreateD3DObjects failed to get an immediate context"); 74 return false; 75 } 76 } 77 if (!mDeviceContextState) { 78 D3D_FEATURE_LEVEL featureLevels[]{D3D_FEATURE_LEVEL_11_1, 79 D3D_FEATURE_LEVEL_11_0}; 80 mDevice->CreateDeviceContextState(0, featureLevels, 2, D3D11_SDK_VERSION, 81 __uuidof(ID3D11Device1), nullptr, 82 &mDeviceContextState); 83 } 84 if (!mDeviceContextState) { 85 NS_WARNING( 86 "VRSession::CreateD3DObjects failed to get a D3D11DeviceContextState"); 87 return false; 88 } 89 return true; 90 } 91 92 ID3D11Device1* VRSession::GetD3DDevice() { return mDevice; } 93 94 ID3D11DeviceContext1* VRSession::GetD3DDeviceContext() { return mContext; } 95 96 ID3DDeviceContextState* VRSession::GetD3DDeviceContextState() { 97 return mDeviceContextState; 98 } 99 100 #endif // defined(XP_WIN) 101 102 bool VRSession::SubmitFrame( 103 const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer) { 104 #if defined(XP_WIN) 105 bool success = false; 106 if (aLayer.textureType == 107 VRLayerTextureType::LayerTextureType_D3D10SurfaceDescriptor) { 108 ID3D11Texture2D* dxTexture = nullptr; 109 mozilla::ipc::FileDescriptor::UniquePlatformHandle handle( 110 aLayer.textureHandle); 111 HRESULT hr = 112 mDevice->OpenSharedResource1(handle.get(), IID_PPV_ARGS(&dxTexture)); 113 if (SUCCEEDED(hr) && dxTexture != nullptr) { 114 // Similar to LockD3DTexture in TextureD3D11.cpp 115 IDXGIKeyedMutex* mutex = nullptr; 116 hr = dxTexture->QueryInterface(IID_PPV_ARGS(&mutex)); 117 if (SUCCEEDED(hr)) { 118 hr = mutex->AcquireSync(0, 1000); 119 # ifdef MOZILLA_INTERNAL_API 120 if (hr == WAIT_TIMEOUT) { 121 gfxDevCrash(LogReason::D3DLockTimeout) << "D3D lock mutex timeout"; 122 } else if (hr == WAIT_ABANDONED) { 123 gfxCriticalNote << "GFX: D3D11 lock mutex abandoned"; 124 } 125 # endif 126 if (SUCCEEDED(hr)) { 127 success = SubmitFrame(aLayer, dxTexture); 128 hr = mutex->ReleaseSync(0); 129 if (FAILED(hr)) { 130 NS_WARNING("Failed to unlock the texture"); 131 } 132 } else { 133 NS_WARNING("Failed to lock the texture"); 134 } 135 136 mutex->Release(); 137 mutex = nullptr; 138 } 139 140 dxTexture->Release(); 141 dxTexture = nullptr; 142 } else { 143 NS_WARNING("Failed to open shared texture"); 144 } 145 146 return SUCCEEDED(hr) && success; 147 } 148 149 #elif defined(XP_MACOSX) 150 151 if (aLayer.textureType == VRLayerTextureType::LayerTextureType_MacIOSurface) { 152 return SubmitFrame(aLayer, aLayer.textureHandle); 153 } 154 155 #endif 156 157 return false; 158 } 159 160 void VRSession::UpdateTrigger(VRControllerState& aState, uint32_t aButtonIndex, 161 float aValue, float aThreshold) { 162 // For OpenVR, the threshold value of ButtonPressed and ButtonTouched is 0.55. 163 // We prefer to let developers to set their own threshold for the adjustment. 164 // Therefore, we don't check ButtonPressed and ButtonTouched with ButtonMask 165 // here. we just check the button value is larger than the threshold value or 166 // not. 167 uint64_t mask = (1ULL << aButtonIndex); 168 aState.triggerValue[aButtonIndex] = aValue; 169 if (aValue > aThreshold) { 170 aState.buttonPressed |= mask; 171 aState.buttonTouched |= mask; 172 } else { 173 aState.buttonPressed &= ~mask; 174 aState.buttonTouched &= ~mask; 175 } 176 } 177 178 void VRSession::SetControllerSelectionAndSqueezeFrameId( 179 VRControllerState& controllerState, uint64_t aFrameId) { 180 // The 1st button, trigger, is its selection action. 181 const bool selectionPressed = controllerState.buttonPressed & 1ULL; 182 if (selectionPressed && controllerState.selectActionStopFrameId >= 183 controllerState.selectActionStartFrameId) { 184 controllerState.selectActionStartFrameId = aFrameId; 185 } else if (!selectionPressed && controllerState.selectActionStartFrameId > 186 controllerState.selectActionStopFrameId) { 187 controllerState.selectActionStopFrameId = aFrameId; 188 } 189 // The 2nd button, squeeze, is its squeeze action. 190 const bool squeezePressed = controllerState.buttonPressed & (1ULL << 1); 191 if (squeezePressed && controllerState.squeezeActionStopFrameId >= 192 controllerState.squeezeActionStartFrameId) { 193 controllerState.squeezeActionStartFrameId = aFrameId; 194 } else if (!squeezePressed && controllerState.squeezeActionStartFrameId > 195 controllerState.squeezeActionStopFrameId) { 196 controllerState.squeezeActionStopFrameId = aFrameId; 197 } 198 } 199 200 bool VRSession::ShouldQuit() const { return mShouldQuit; }