From 126828131d9df2a715c74742dc90559c7c939bdd Mon Sep 17 00:00:00 2001 From: James Urquhart Date: Mon, 25 Apr 2016 23:26:27 +0100 Subject: [PATCH] Improve openvr, also add a module for it. --- Engine/source/gfx/gfxInit.cpp | 22 ++-- .../platform/input/openVR/openVRProvider.cpp | 118 +++++++++++++++++- .../platform/input/openVR/openVRProvider.h | 43 +++++++ Tools/CMake/modules/module_openvr.cmake | 30 +++++ 4 files changed, 199 insertions(+), 14 deletions(-) create mode 100644 Tools/CMake/modules/module_openvr.cmake diff --git a/Engine/source/gfx/gfxInit.cpp b/Engine/source/gfx/gfxInit.cpp index bb5e560ac..69ea43d0c 100644 --- a/Engine/source/gfx/gfxInit.cpp +++ b/Engine/source/gfx/gfxInit.cpp @@ -293,19 +293,19 @@ GFXAdapter *GFXInit::getBestAdapterChoice() // Get the user's preference for device... const String renderer = Con::getVariable("$pref::Video::displayDevice"); const String outputDevice = Con::getVariable("$pref::Video::displayOutputDevice"); - const String adapterDevice = Con::getVariable("$Video::forceDisplayAdapter"); + const String adapterDevice = Con::getVariable("$Video::forceDisplayAdapter"); - GFXAdapterType adapterType = getAdapterTypeFromName(renderer.c_str());; - GFXAdapter *adapter; + GFXAdapterType adapterType = getAdapterTypeFromName(renderer.c_str());; + GFXAdapter *adapter; - if (adapterDevice.isEmpty()) - { - adapter = chooseAdapter(adapterType, outputDevice.c_str()); - } - else - { - adapter = chooseAdapter(adapterType, dAtoi(adapterDevice.c_str())); - } + if (adapterDevice.isEmpty()) + { + adapter = chooseAdapter(adapterType, outputDevice.c_str()); + } + else if (dAtoi(adapterDevice.c_str()) != -1) + { + adapter = chooseAdapter(adapterType, dAtoi(adapterDevice.c_str())); + } // Did they have one? Return it. if(adapter) diff --git a/Engine/source/platform/input/openVR/openVRProvider.cpp b/Engine/source/platform/input/openVR/openVRProvider.cpp index 01a9b1dfb..bf03d99b7 100644 --- a/Engine/source/platform/input/openVR/openVRProvider.cpp +++ b/Engine/source/platform/input/openVR/openVRProvider.cpp @@ -11,6 +11,11 @@ #include "gfx/D3D11/gfxD3D11EnumTranslate.h" #include "gfx/gfxStringEnumTranslate.h" + +#include "gfx/D3D9/gfxD3D9Device.h" +#include "gfx/D3D9/gfxD3D9TextureObject.h" +#include "gfx/D3D9/gfxD3D9EnumTranslate.h" + /* #include "gfx/gl/gfxGLDevice.h" #include "gfx/gl/gfxGLTextureObject.h" @@ -20,6 +25,8 @@ #include "platform/input/oculusVR/oculusVRUtil.h" +//------------------------------------------------------------ + U32 OpenVRProvider::OVR_SENSORROT[vr::k_unMaxTrackedDeviceCount] = { 0 }; U32 OpenVRProvider::OVR_SENSORROTANG[vr::k_unMaxTrackedDeviceCount] = { 0 }; U32 OpenVRProvider::OVR_SENSORVELOCITY[vr::k_unMaxTrackedDeviceCount] = { 0 }; @@ -108,6 +115,9 @@ bool OpenVRRenderState::setupRenderTargets(U32 mode) mEyeRT[0] = mEyeRT[1] = mStereoRT; + mOutputEyeTextures[0].init(newRTSize.x, newRTSize.y, GFXFormatR8G8B8A8, &VRTextureProfile, "OpenVR Stereo RT Color OUTPUT"); + mOutputEyeTextures[1].init(newRTSize.x, newRTSize.y, GFXFormatR8G8B8A8, &VRTextureProfile, "OpenVR Stereo RT Color OUTPUT"); + return true; } @@ -272,6 +282,9 @@ void OpenVRRenderState::reset(vr::IVRSystem* hmd) mDistortionVerts = NULL; mDistortionInds = NULL; + mOutputEyeTextures[0].clear(); + mOutputEyeTextures[1].clear(); + if (!mHMD) return; @@ -303,6 +316,7 @@ OpenVRProvider::OpenVRProvider() : buildInputCodeTable(); GFXDevice::getDeviceEventSignal().notify(this, &OpenVRProvider::_handleDeviceEvent); INPUTMGR->registerDevice(this); + dMemset(&mLUID, '\0', sizeof(mLUID)); } OpenVRProvider::~OpenVRProvider() @@ -334,6 +348,49 @@ bool OpenVRProvider::enable() return false; } + dMemset(&mLUID, '\0', sizeof(mLUID)); + +#ifdef TORQUE_OS_WIN32 + + // For windows we need to lookup the DXGI record for this and grab the LUID for the display adapter. We need the LUID since + // T3D uses EnumAdapters1 not EnumAdapters whereas openvr uses EnumAdapters. + int32_t AdapterIdx; + IDXGIAdapter* EnumAdapter; + IDXGIFactory1* DXGIFactory; + mHMD->GetDXGIOutputInfo(&AdapterIdx); + // Get the LUID of the device + + HRESULT hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast(&DXGIFactory)); + + if (FAILED(hr)) + AssertFatal(false, "OpenVRProvider::enable -> CreateDXGIFactory1 call failure"); + + hr = DXGIFactory->EnumAdapters(AdapterIdx, &EnumAdapter); + + if (FAILED(hr)) + { + Con::warnf("VR: HMD device has an invalid adapter."); + } + else + { + DXGI_ADAPTER_DESC desc; + hr = EnumAdapter->GetDesc(&desc); + if (FAILED(hr)) + { + Con::warnf("VR: HMD device has an invalid adapter."); + } + else + { + dMemcpy(&mLUID, &desc.AdapterLuid, sizeof(mLUID)); + } + SAFE_RELEASE(EnumAdapter); + } + + SAFE_RELEASE(DXGIFactory); +#endif + + + mRenderModels = (vr::IVRRenderModels *)vr::VR_GetGenericInterface(vr::IVRRenderModels_Version, &eError); if (!mRenderModels) { @@ -441,6 +498,9 @@ bool OpenVRProvider::process() if (!mHMD) return true; + if (!vr::VRCompositor()) + return true; + // Process SteamVR events vr::VREvent_t event; while (mHMD->PollNextEvent(&event, sizeof(event))) @@ -570,7 +630,7 @@ void OpenVRProvider::setDrawCanvas(GuiCanvas *canvas) if (!vr::VRCompositor()) { - printf("Compositor initialization failed. See log file for details\n"); + Con::errorf("VR: Compositor initialization failed. See log file for details\n"); return; } @@ -614,16 +674,30 @@ void OpenVRProvider::onEyeRendered(U32 index) if (!mHMD) return; + vr::EVRCompositorError err = vr::VRCompositorError_None; + + GFXTexHandle eyeTex = mHMDRenderState.mOutputEyeTextures[index].getTextureHandle(); + mHMDRenderState.mEyeRT[0]->resolveTo(eyeTex); + mHMDRenderState.mOutputEyeTextures[index].advance(); + if (GFX->getAdapterType() == Direct3D11) { - vr::Texture_t eyeTexture = { (void*)static_cast(mHMDRenderState.mStereoRenderTextures[index].getPointer())->get2DTex(), vr::API_DirectX, vr::ColorSpace_Gamma }; - vr::VRCompositor()->Submit((vr::EVREye)(vr::Eye_Left + index), &eyeTexture); + GFXFormat fmt1 = eyeTex->getFormat(); + vr::Texture_t eyeTexture = { (void*)static_cast(eyeTex.getPointer())->get2DTex(), vr::API_DirectX, vr::ColorSpace_Gamma }; + err = vr::VRCompositor()->Submit((vr::EVREye)(vr::Eye_Left + index), &eyeTexture); + } + else if (GFX->getAdapterType() == Direct3D9) + { + //vr::Texture_t eyeTexture = { (void*)static_cast(mHMDRenderState.mStereoRenderTextures[index].getPointer())->get2DTex(), vr::API_DirectX, vr::ColorSpace_Gamma }; + //err = vr::VRCompositor()->Submit((vr::EVREye)(vr::Eye_Left + index), &eyeTexture); } else if (GFX->getAdapterType() == OpenGL) {/* vr::Texture_t eyeTexture = { (void*)static_cast(mHMDRenderState.mStereoRenderTextures[index].getPointer())->getHandle(), vr::API_OpenGL, vr::ColorSpace_Gamma }; vr::VRCompositor()->Submit((vr::EVREye)(vr::Eye_Left + index), &eyeTexture);*/ } + + AssertFatal(err != vr::VRCompositorError_None, "VR compositor error!"); } bool OpenVRProvider::_handleDeviceEvent(GFXDevice::GFXDeviceEventType evt) @@ -675,6 +749,29 @@ bool OpenVRProvider::_handleDeviceEvent(GFXDevice::GFXDeviceEventType evt) return true; } +S32 OpenVRProvider::getDisplayDeviceId() const +{ + return -1; +#ifdef TORQUE_OS_WIN32 + if (GFX->getAdapterType() == Direct3D11) + { + Vector adapterList; + GFXD3D11Device::enumerateAdapters(adapterList); + + for (U32 i = 0, sz = adapterList.size(); i < sz; i++) + { + GFXAdapter* adapter = adapterList[i]; + if (dMemcmp(&adapter->mLUID, &mLUID, sizeof(mLUID)) == 0) + { + return adapter->mIndex; + } + } + } +#endif + + return -1; +} + void OpenVRProvider::processVREvent(const vr::VREvent_t & event) { switch (event.eventType) @@ -870,6 +967,21 @@ DefineEngineFunction(setOpenVRHMDAsGameConnectionDisplayDevice, bool, (GameConne return true; } + +DefineEngineFunction(OpenVRGetDisplayDeviceId, S32, (), , + "@brief MacOS display ID.\n\n" + "@param index The HMD index.\n" + "@return The ID of the HMD display device, if any.\n" + "@ingroup Game") +{ + if (!ManagedSingleton::instanceOrNull()) + { + return -1; + } + + return ManagedSingleton::instance()->getDisplayDeviceId(); +} + DefineEngineFunction(OpenVRResetSensors, void, (), , "@brief Resets all Oculus VR sensors.\n\n" "This resets all sensor orientations such that their 'normal' rotation " diff --git a/Engine/source/platform/input/openVR/openVRProvider.h b/Engine/source/platform/input/openVR/openVRProvider.h index 053fd518a..5006269a1 100644 --- a/Engine/source/platform/input/openVR/openVRProvider.h +++ b/Engine/source/platform/input/openVR/openVRProvider.h @@ -20,6 +20,44 @@ class OpenVRHMDDevice; +class VRTextureSet +{ +public: + static const int TextureCount = 2; + GFXTexHandle mTextures[2]; + U32 mIndex; + + VRTextureSet() : mIndex(0) + { + } + + void init(U32 width, U32 height, GFXFormat fmt, GFXTextureProfile *profile, const String &desc) + { + for (U32 i = 0; i < TextureCount; i++) + { + mTextures[i].set(width, height, fmt, profile, desc); + } + } + + void clear() + { + for (U32 i = 0; i < TextureCount; i++) + { + mTextures[i] = NULL; + } + } + + void advance() + { + mIndex = (mIndex + 1) & TextureCount; + } + + GFXTexHandle& getTextureHandle() + { + return mTextures[mIndex]; + } +}; + struct OpenVRRenderState { vr::IVRSystem *mHMD; @@ -38,6 +76,8 @@ struct OpenVRRenderState GFXVertexBufferHandle mDistortionVerts; GFXPrimitiveBufferHandle mDistortionInds; + VRTextureSet mOutputEyeTextures[2]; + bool setupRenderTargets(U32 mode); void setupDistortion(); @@ -114,6 +154,8 @@ public: virtual void onEyeRendered(U32 index); bool _handleDeviceEvent(GFXDevice::GFXDeviceEventType evt); + + S32 getDisplayDeviceId() const; /// } /// @name OpenVR handling @@ -140,6 +182,7 @@ public: char mDeviceClassChar[vr::k_unMaxTrackedDeviceCount]; OpenVRRenderState mHMDRenderState; + GFXAdapterLUID mLUID; /// } GuiCanvas* mDrawCanvas; diff --git a/Tools/CMake/modules/module_openvr.cmake b/Tools/CMake/modules/module_openvr.cmake new file mode 100644 index 000000000..66a490348 --- /dev/null +++ b/Tools/CMake/modules/module_openvr.cmake @@ -0,0 +1,30 @@ + +# module openvr + +option(TORQUE_OPENVR "Enable openvr module" OFF) +mark_as_advanced(TORQUE_OPENVR) +if(TORQUE_OPENVR) + if(TORQUE_OCULUSVR_SDK_PATH STREQUAL "") + set(TORQUE_OPENVR_SDK_PATH "" CACHE PATH "openvr library path" FORCE) + endif() +else() # hide variable + set(TORQUE_OPENVR_SDK_PATH "" CACHE INTERNAL "" FORCE) +endif() + +if(TORQUE_OPENVR) + # Source + addPathRec( "${srcDir}/platform/input/openvr" ) + + # Includes + addInclude( "${TORQUE_OPENVR_SDK_PATH}/headers" ) + + # Libs + if( WIN32 ) + if( TORQUE_CPU_X64 ) + link_directories( "${TORQUE_OPENVR_SDK_PATH}/lib/win64" ) + else() + link_directories( "${TORQUE_OPENVR_SDK_PATH}/lib/win32" ) + endif() + addLib( "openvr_api" ) + endif() +endif()