diff --git a/cmake/externals/openvr/CMakeLists.txt b/cmake/externals/openvr/CMakeLists.txt index 9ef95b17da..3fe7df44d0 100644 --- a/cmake/externals/openvr/CMakeLists.txt +++ b/cmake/externals/openvr/CMakeLists.txt @@ -7,8 +7,8 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) ExternalProject_Add( ${EXTERNAL_NAME} - URL https://github.com/ValveSoftware/openvr/archive/v0.9.12.zip - URL_MD5 c08dced68ce4e341e1467e6814ae419d + URL https://github.com/ValveSoftware/openvr/archive/v0.9.15.zip + URL_MD5 0ff8560b49b6da1150fcc47360e8ceca CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp index 0be66bab67..cadb4a2e40 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp @@ -39,6 +39,7 @@ glm::mat4 OculusBaseDisplayPlugin::getHeadPose(uint32_t frameIndex) const { bool OculusBaseDisplayPlugin::isSupported() const { if (!OVR_SUCCESS(ovr_Initialize(nullptr))) { + qDebug() << "OculusBaseDisplayPlugin : ovr_Initialize() failed"; return false; } @@ -48,6 +49,7 @@ bool OculusBaseDisplayPlugin::isSupported() const { if (!OVR_SUCCESS(result)) { ovrErrorInfo error; ovr_GetLastErrorInfo(&error); + qDebug() << "OculusBaseDisplayPlugin : ovr_Create() failed" << result << error.Result << error.ErrorString; ovr_Shutdown(); return false; } diff --git a/plugins/openvr/CMakeLists.txt b/plugins/openvr/CMakeLists.txt index c3c4771276..878df3bfa5 100644 --- a/plugins/openvr/CMakeLists.txt +++ b/plugins/openvr/CMakeLists.txt @@ -6,20 +6,17 @@ # See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html # -# OpenVR is disabled until a) it works with threaded present and -# b) it doesn't interfere with Oculus SDK 0.8 -if (FALSE) -#if (WIN32) +if (WIN32) # we're using static GLEW, so define GLEW_STATIC add_definitions(-DGLEW_STATIC) set(TARGET_NAME openvr) setup_hifi_plugin(OpenGL Script Qml Widgets) - link_hifi_libraries(shared gl networking controllers - plugins display-plugins input-plugins script-engine + link_hifi_libraries(shared gl networking controllers + plugins display-plugins input-plugins script-engine render-utils model gpu render model-networking fbx) include_hifi_library_headers(octree) - + add_dependency_external_projects(OpenVR) find_package(OpenVR REQUIRED) target_include_directories(${TARGET_NAME} PRIVATE ${OPENVR_INCLUDE_DIRS}) diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp index 7fb70180c4..508c89803d 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp +++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp @@ -32,12 +32,15 @@ const QString OpenVrDisplayPlugin::NAME("OpenVR (Vive)"); const QString StandingHMDSensorMode = "Standing HMD Sensor Mode"; // this probably shouldn't be hardcoded here static vr::IVRCompositor* _compositor{ nullptr }; +static vr::TrackedDevicePose_t _presentThreadTrackedDevicePose[vr::k_unMaxTrackedDeviceCount]; vr::TrackedDevicePose_t _trackedDevicePose[vr::k_unMaxTrackedDeviceCount]; mat4 _trackedDevicePoseMat4[vr::k_unMaxTrackedDeviceCount]; static mat4 _sensorResetMat; static uvec2 _windowSize; static uvec2 _renderTargetSize; + + struct PerEyeData { //uvec2 _viewportOrigin; //uvec2 _viewportSize; @@ -69,10 +72,7 @@ mat4 toGlm(const vr::HmdMatrix34_t& m) { } bool OpenVrDisplayPlugin::isSupported() const { - auto hmd = acquireOpenVrSystem(); - bool success = nullptr != hmd; - releaseOpenVrSystem(); - return success; + return vr::VR_IsHmdPresent(); } void OpenVrDisplayPlugin::activate() { @@ -87,11 +87,16 @@ void OpenVrDisplayPlugin::activate() { // Recommended render target size is per-eye, so double the X size for // left + right eyes _renderTargetSize.x *= 2; - openvr_for_each_eye([&](vr::Hmd_Eye eye) { - PerEyeData& eyeData = _eyesData[eye]; - eyeData._projectionMatrix = toGlm(_hmd->GetProjectionMatrix(eye, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, vr::API_OpenGL)); - eyeData._eyeOffset = toGlm(_hmd->GetEyeToHeadTransform(eye)); - }); + + { + Lock lock(_poseMutex); + openvr_for_each_eye([&](vr::Hmd_Eye eye) { + PerEyeData& eyeData = _eyesData[eye]; + eyeData._projectionMatrix = toGlm(_hmd->GetProjectionMatrix(eye, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, vr::API_OpenGL)); + eyeData._eyeOffset = toGlm(_hmd->GetEyeToHeadTransform(eye)); + }); + } + _compositor = vr::VRCompositor(); Q_ASSERT(_compositor); WindowOpenGLDisplayPlugin::activate(); @@ -115,6 +120,10 @@ void OpenVrDisplayPlugin::customizeContext() { glGetError(); }); WindowOpenGLDisplayPlugin::customizeContext(); + + enableVsync(false); + // Only enable mirroring if we know vsync is disabled + _enablePreview = !isVsyncEnabled(); } uvec2 OpenVrDisplayPlugin::getRecommendedRenderSize() const { @@ -126,25 +135,24 @@ mat4 OpenVrDisplayPlugin::getProjection(Eye eye, const mat4& baseProjection) con if (eye == Mono) { eye = Left; } + Lock lock(_poseMutex); return _eyesData[eye]._projectionMatrix; } void OpenVrDisplayPlugin::resetSensors() { - _sensorResetMat = glm::inverse(cancelOutRollAndPitch(_trackedDevicePoseMat4[0])); + Lock lock(_poseMutex); + glm::mat4 m = toGlm(_trackedDevicePose[0].mDeviceToAbsoluteTracking); + _sensorResetMat = glm::inverse(cancelOutRollAndPitch(m)); } glm::mat4 OpenVrDisplayPlugin::getEyeToHeadTransform(Eye eye) const { + Lock lock(_poseMutex); return _eyesData[eye]._eyeOffset; } glm::mat4 OpenVrDisplayPlugin::getHeadPose(uint32_t frameIndex) const { - glm::mat4 result; - { - Lock lock(_mutex); - result = _trackedDevicePoseMat4[0]; - - } - return result; + Lock lock(_poseMutex); + return _trackedDevicePoseMat4[0]; } @@ -156,17 +164,40 @@ void OpenVrDisplayPlugin::internalPresent() { // Flip y-axis since GL UV coords are backwards. static vr::VRTextureBounds_t leftBounds{ 0, 0, 0.5f, 1 }; static vr::VRTextureBounds_t rightBounds{ 0.5f, 0, 1, 1 }; - vr::Texture_t texture{ (void*)_currentSceneTexture, vr::API_OpenGL, vr::ColorSpace_Auto }; - { - Lock lock(_mutex); - _compositor->Submit(vr::Eye_Left, &texture, &leftBounds); - _compositor->Submit(vr::Eye_Right, &texture, &rightBounds); + + // screen preview mirroring + if (_enablePreview) { + auto windowSize = toGlm(_window->size()); + if (_monoPreview) { + glViewport(0, 0, windowSize.x * 2, windowSize.y); + glScissor(0, windowSize.y, windowSize.x, windowSize.y); + } else { + glViewport(0, 0, windowSize.x, windowSize.y); + } + glBindTexture(GL_TEXTURE_2D, _currentSceneTexture); + GLenum err = glGetError(); + Q_ASSERT(0 == err); + drawUnitQuad(); } + + vr::Texture_t texture{ (void*)_currentSceneTexture, vr::API_OpenGL, vr::ColorSpace_Auto }; + + _compositor->Submit(vr::Eye_Left, &texture, &leftBounds); + _compositor->Submit(vr::Eye_Right, &texture, &rightBounds); + glFinish(); + + if (_enablePreview) { + swapBuffers(); + } + + _compositor->WaitGetPoses(_presentThreadTrackedDevicePose, vr::k_unMaxTrackedDeviceCount, nullptr, 0); + { - Lock lock(_mutex); - _compositor->WaitGetPoses(_trackedDevicePose, vr::k_unMaxTrackedDeviceCount, nullptr, 0); + // copy and process _presentThreadTrackedDevicePoses + Lock lock(_poseMutex); for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { + _trackedDevicePose[i] = _presentThreadTrackedDevicePose[i]; _trackedDevicePoseMat4[i] = _sensorResetMat * toGlm(_trackedDevicePose[i].mDeviceToAbsoluteTracking); } openvr_for_each_eye([&](vr::Hmd_Eye eye) { diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.h b/plugins/openvr/src/OpenVrDisplayPlugin.h index e290368de0..ac72b0908b 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.h +++ b/plugins/openvr/src/OpenVrDisplayPlugin.h @@ -45,5 +45,8 @@ protected: private: vr::IVRSystem* _hmd { nullptr }; static const QString NAME; + bool _enablePreview { false }; + bool _monoPreview { true }; + mutable Mutex _poseMutex; }; diff --git a/plugins/openvr/src/OpenVrHelpers.cpp b/plugins/openvr/src/OpenVrHelpers.cpp index 7020fcb40d..66a886b90e 100644 --- a/plugins/openvr/src/OpenVrHelpers.cpp +++ b/plugins/openvr/src/OpenVrHelpers.cpp @@ -23,11 +23,11 @@ using Lock = std::unique_lock; static int refCount { 0 }; static Mutex mutex; static vr::IVRSystem* activeHmd { nullptr }; -static bool hmdPresent = vr::VR_IsHmdPresent(); static const uint32_t RELEASE_OPENVR_HMD_DELAY_MS = 5000; vr::IVRSystem* acquireOpenVrSystem() { + bool hmdPresent = vr::VR_IsHmdPresent(); if (hmdPresent) { Lock lock(mutex); if (!activeHmd) { @@ -40,6 +40,8 @@ vr::IVRSystem* acquireOpenVrSystem() { qCDebug(displayplugins) << "openvr: incrementing refcount"; ++refCount; } + } else { + qCDebug(displayplugins) << "openvr: no hmd present"; } return activeHmd; } @@ -51,24 +53,7 @@ void releaseOpenVrSystem() { --refCount; if (0 == refCount) { qCDebug(displayplugins) << "openvr: zero refcount, deallocate VR system"; - // Avoid spamming the VR system with activate/deactivate calls at system startup by - // putting in a delay before we destory the shutdown the VR subsystem - - // FIXME releasing the VR system at all seems to trigger an exception deep inside the Oculus DLL. - // disabling for now. - //QTimer* releaseTimer = new QTimer(); - //releaseTimer->singleShot(RELEASE_OPENVR_HMD_DELAY_MS, [releaseTimer] { - // Lock lock(mutex); - // qDebug() << "Delayed openvr destroy activated"; - // if (0 == refCount && nullptr != activeHmd) { - // qDebug() << "Delayed openvr destroy: releasing resources"; - // activeHmd = nullptr; - // vr::VR_Shutdown(); - // } else { - // qDebug() << "Delayed openvr destroy: HMD still in use"; - // } - // releaseTimer->deleteLater(); - //}); + vr::VR_Shutdown(); } } } diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 0e3a0be72b..522c7f9c3d 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -48,10 +48,7 @@ static const QString RENDER_CONTROLLERS = "Render Hand Controllers"; const QString ViveControllerManager::NAME = "OpenVR"; bool ViveControllerManager::isSupported() const { - auto hmd = acquireOpenVrSystem(); - bool success = hmd != nullptr; - releaseOpenVrSystem(); - return success; + return vr::VR_IsHmdPresent(); } void ViveControllerManager::activate() { @@ -66,10 +63,12 @@ void ViveControllerManager::activate() { } Q_ASSERT(_hmd); + // OpenVR provides 3d mesh representations of the controllers + // Disabled controller rendering code + /* auto renderModels = vr::VRRenderModels(); vr::RenderModel_t model; - /* if (!_hmd->LoadRenderModel(CONTROLLER_MODEL_STRING, &model)) { qDebug() << QString("Unable to load render model %1\n").arg(CONTROLLER_MODEL_STRING); } else { @@ -145,6 +144,7 @@ void ViveControllerManager::deactivate() { void ViveControllerManager::updateRendering(RenderArgs* args, render::ScenePointer scene, render::PendingChanges pendingChanges) { PerformanceTimer perfTimer("ViveControllerManager::updateRendering"); + /* if (_modelLoaded) { //auto controllerPayload = new render::Payload(this); //auto controllerPayloadPointer = ViveControllerManager::PayloadPointer(controllerPayload); @@ -175,9 +175,11 @@ void ViveControllerManager::updateRendering(RenderArgs* args, render::ScenePoint } }); } + */ } void ViveControllerManager::renderHand(const controller::Pose& pose, gpu::Batch& batch, int sign) { + /* auto userInputMapper = DependencyManager::get(); Transform transform(userInputMapper->getSensorToWorldMat()); transform.postTranslate(pose.getTranslation() + pose.getRotation() * glm::vec3(0, 0, CONTROLLER_LENGTH_OFFSET)); @@ -199,6 +201,7 @@ void ViveControllerManager::renderHand(const controller::Pose& pose, gpu::Batch& // mesh->getVertexBuffer()._stride); batch.setIndexBuffer(gpu::UINT16, mesh->getIndexBuffer()._buffer, 0); batch.drawIndexed(gpu::TRIANGLES, mesh->getNumIndices(), 0); + */ }