Merge pull request #7067 from hyperlogic/tony/vive-support

Re-enable OpenVR support
This commit is contained in:
Brad Davis 2016-02-10 19:04:35 -08:00
commit ff3c934c6c
7 changed files with 78 additions and 57 deletions

View file

@ -7,8 +7,8 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
ExternalProject_Add( ExternalProject_Add(
${EXTERNAL_NAME} ${EXTERNAL_NAME}
URL https://github.com/ValveSoftware/openvr/archive/v0.9.12.zip URL https://github.com/ValveSoftware/openvr/archive/v0.9.15.zip
URL_MD5 c08dced68ce4e341e1467e6814ae419d URL_MD5 0ff8560b49b6da1150fcc47360e8ceca
CONFIGURE_COMMAND "" CONFIGURE_COMMAND ""
BUILD_COMMAND "" BUILD_COMMAND ""
INSTALL_COMMAND "" INSTALL_COMMAND ""

View file

@ -39,6 +39,7 @@ glm::mat4 OculusBaseDisplayPlugin::getHeadPose(uint32_t frameIndex) const {
bool OculusBaseDisplayPlugin::isSupported() const { bool OculusBaseDisplayPlugin::isSupported() const {
if (!OVR_SUCCESS(ovr_Initialize(nullptr))) { if (!OVR_SUCCESS(ovr_Initialize(nullptr))) {
qDebug() << "OculusBaseDisplayPlugin : ovr_Initialize() failed";
return false; return false;
} }
@ -48,6 +49,7 @@ bool OculusBaseDisplayPlugin::isSupported() const {
if (!OVR_SUCCESS(result)) { if (!OVR_SUCCESS(result)) {
ovrErrorInfo error; ovrErrorInfo error;
ovr_GetLastErrorInfo(&error); ovr_GetLastErrorInfo(&error);
qDebug() << "OculusBaseDisplayPlugin : ovr_Create() failed" << result << error.Result << error.ErrorString;
ovr_Shutdown(); ovr_Shutdown();
return false; return false;
} }

View file

@ -6,20 +6,17 @@
# See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html # 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 if (WIN32)
# b) it doesn't interfere with Oculus SDK 0.8
if (FALSE)
#if (WIN32)
# we're using static GLEW, so define GLEW_STATIC # we're using static GLEW, so define GLEW_STATIC
add_definitions(-DGLEW_STATIC) add_definitions(-DGLEW_STATIC)
set(TARGET_NAME openvr) set(TARGET_NAME openvr)
setup_hifi_plugin(OpenGL Script Qml Widgets) setup_hifi_plugin(OpenGL Script Qml Widgets)
link_hifi_libraries(shared gl networking controllers link_hifi_libraries(shared gl networking controllers
plugins display-plugins input-plugins script-engine plugins display-plugins input-plugins script-engine
render-utils model gpu render model-networking fbx) render-utils model gpu render model-networking fbx)
include_hifi_library_headers(octree) include_hifi_library_headers(octree)
add_dependency_external_projects(OpenVR) add_dependency_external_projects(OpenVR)
find_package(OpenVR REQUIRED) find_package(OpenVR REQUIRED)
target_include_directories(${TARGET_NAME} PRIVATE ${OPENVR_INCLUDE_DIRS}) target_include_directories(${TARGET_NAME} PRIVATE ${OPENVR_INCLUDE_DIRS})

View file

@ -32,12 +32,15 @@ const QString OpenVrDisplayPlugin::NAME("OpenVR (Vive)");
const QString StandingHMDSensorMode = "Standing HMD Sensor Mode"; // this probably shouldn't be hardcoded here const QString StandingHMDSensorMode = "Standing HMD Sensor Mode"; // this probably shouldn't be hardcoded here
static vr::IVRCompositor* _compositor{ nullptr }; static vr::IVRCompositor* _compositor{ nullptr };
static vr::TrackedDevicePose_t _presentThreadTrackedDevicePose[vr::k_unMaxTrackedDeviceCount];
vr::TrackedDevicePose_t _trackedDevicePose[vr::k_unMaxTrackedDeviceCount]; vr::TrackedDevicePose_t _trackedDevicePose[vr::k_unMaxTrackedDeviceCount];
mat4 _trackedDevicePoseMat4[vr::k_unMaxTrackedDeviceCount]; mat4 _trackedDevicePoseMat4[vr::k_unMaxTrackedDeviceCount];
static mat4 _sensorResetMat; static mat4 _sensorResetMat;
static uvec2 _windowSize; static uvec2 _windowSize;
static uvec2 _renderTargetSize; static uvec2 _renderTargetSize;
struct PerEyeData { struct PerEyeData {
//uvec2 _viewportOrigin; //uvec2 _viewportOrigin;
//uvec2 _viewportSize; //uvec2 _viewportSize;
@ -69,10 +72,7 @@ mat4 toGlm(const vr::HmdMatrix34_t& m) {
} }
bool OpenVrDisplayPlugin::isSupported() const { bool OpenVrDisplayPlugin::isSupported() const {
auto hmd = acquireOpenVrSystem(); return vr::VR_IsHmdPresent();
bool success = nullptr != hmd;
releaseOpenVrSystem();
return success;
} }
void OpenVrDisplayPlugin::activate() { void OpenVrDisplayPlugin::activate() {
@ -87,11 +87,16 @@ void OpenVrDisplayPlugin::activate() {
// Recommended render target size is per-eye, so double the X size for // Recommended render target size is per-eye, so double the X size for
// left + right eyes // left + right eyes
_renderTargetSize.x *= 2; _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)); Lock lock(_poseMutex);
eyeData._eyeOffset = toGlm(_hmd->GetEyeToHeadTransform(eye)); 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(); _compositor = vr::VRCompositor();
Q_ASSERT(_compositor); Q_ASSERT(_compositor);
WindowOpenGLDisplayPlugin::activate(); WindowOpenGLDisplayPlugin::activate();
@ -115,6 +120,10 @@ void OpenVrDisplayPlugin::customizeContext() {
glGetError(); glGetError();
}); });
WindowOpenGLDisplayPlugin::customizeContext(); WindowOpenGLDisplayPlugin::customizeContext();
enableVsync(false);
// Only enable mirroring if we know vsync is disabled
_enablePreview = !isVsyncEnabled();
} }
uvec2 OpenVrDisplayPlugin::getRecommendedRenderSize() const { uvec2 OpenVrDisplayPlugin::getRecommendedRenderSize() const {
@ -126,25 +135,24 @@ mat4 OpenVrDisplayPlugin::getProjection(Eye eye, const mat4& baseProjection) con
if (eye == Mono) { if (eye == Mono) {
eye = Left; eye = Left;
} }
Lock lock(_poseMutex);
return _eyesData[eye]._projectionMatrix; return _eyesData[eye]._projectionMatrix;
} }
void OpenVrDisplayPlugin::resetSensors() { 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 { glm::mat4 OpenVrDisplayPlugin::getEyeToHeadTransform(Eye eye) const {
Lock lock(_poseMutex);
return _eyesData[eye]._eyeOffset; return _eyesData[eye]._eyeOffset;
} }
glm::mat4 OpenVrDisplayPlugin::getHeadPose(uint32_t frameIndex) const { glm::mat4 OpenVrDisplayPlugin::getHeadPose(uint32_t frameIndex) const {
glm::mat4 result; Lock lock(_poseMutex);
{ return _trackedDevicePoseMat4[0];
Lock lock(_mutex);
result = _trackedDevicePoseMat4[0];
}
return result;
} }
@ -156,17 +164,40 @@ void OpenVrDisplayPlugin::internalPresent() {
// Flip y-axis since GL UV coords are backwards. // Flip y-axis since GL UV coords are backwards.
static vr::VRTextureBounds_t leftBounds{ 0, 0, 0.5f, 1 }; static vr::VRTextureBounds_t leftBounds{ 0, 0, 0.5f, 1 };
static vr::VRTextureBounds_t rightBounds{ 0.5f, 0, 1, 1 }; static vr::VRTextureBounds_t rightBounds{ 0.5f, 0, 1, 1 };
vr::Texture_t texture{ (void*)_currentSceneTexture, vr::API_OpenGL, vr::ColorSpace_Auto };
{ // screen preview mirroring
Lock lock(_mutex); if (_enablePreview) {
_compositor->Submit(vr::Eye_Left, &texture, &leftBounds); auto windowSize = toGlm(_window->size());
_compositor->Submit(vr::Eye_Right, &texture, &rightBounds); 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(); glFinish();
if (_enablePreview) {
swapBuffers();
}
_compositor->WaitGetPoses(_presentThreadTrackedDevicePose, vr::k_unMaxTrackedDeviceCount, nullptr, 0);
{ {
Lock lock(_mutex); // copy and process _presentThreadTrackedDevicePoses
_compositor->WaitGetPoses(_trackedDevicePose, vr::k_unMaxTrackedDeviceCount, nullptr, 0); Lock lock(_poseMutex);
for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) {
_trackedDevicePose[i] = _presentThreadTrackedDevicePose[i];
_trackedDevicePoseMat4[i] = _sensorResetMat * toGlm(_trackedDevicePose[i].mDeviceToAbsoluteTracking); _trackedDevicePoseMat4[i] = _sensorResetMat * toGlm(_trackedDevicePose[i].mDeviceToAbsoluteTracking);
} }
openvr_for_each_eye([&](vr::Hmd_Eye eye) { openvr_for_each_eye([&](vr::Hmd_Eye eye) {

View file

@ -45,5 +45,8 @@ protected:
private: private:
vr::IVRSystem* _hmd { nullptr }; vr::IVRSystem* _hmd { nullptr };
static const QString NAME; static const QString NAME;
bool _enablePreview { false };
bool _monoPreview { true };
mutable Mutex _poseMutex;
}; };

View file

@ -23,11 +23,11 @@ using Lock = std::unique_lock<Mutex>;
static int refCount { 0 }; static int refCount { 0 };
static Mutex mutex; static Mutex mutex;
static vr::IVRSystem* activeHmd { nullptr }; static vr::IVRSystem* activeHmd { nullptr };
static bool hmdPresent = vr::VR_IsHmdPresent();
static const uint32_t RELEASE_OPENVR_HMD_DELAY_MS = 5000; static const uint32_t RELEASE_OPENVR_HMD_DELAY_MS = 5000;
vr::IVRSystem* acquireOpenVrSystem() { vr::IVRSystem* acquireOpenVrSystem() {
bool hmdPresent = vr::VR_IsHmdPresent();
if (hmdPresent) { if (hmdPresent) {
Lock lock(mutex); Lock lock(mutex);
if (!activeHmd) { if (!activeHmd) {
@ -40,6 +40,8 @@ vr::IVRSystem* acquireOpenVrSystem() {
qCDebug(displayplugins) << "openvr: incrementing refcount"; qCDebug(displayplugins) << "openvr: incrementing refcount";
++refCount; ++refCount;
} }
} else {
qCDebug(displayplugins) << "openvr: no hmd present";
} }
return activeHmd; return activeHmd;
} }
@ -51,24 +53,7 @@ void releaseOpenVrSystem() {
--refCount; --refCount;
if (0 == refCount) { if (0 == refCount) {
qCDebug(displayplugins) << "openvr: zero refcount, deallocate VR system"; qCDebug(displayplugins) << "openvr: zero refcount, deallocate VR system";
// Avoid spamming the VR system with activate/deactivate calls at system startup by vr::VR_Shutdown();
// 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();
//});
} }
} }
} }

View file

@ -48,10 +48,7 @@ static const QString RENDER_CONTROLLERS = "Render Hand Controllers";
const QString ViveControllerManager::NAME = "OpenVR"; const QString ViveControllerManager::NAME = "OpenVR";
bool ViveControllerManager::isSupported() const { bool ViveControllerManager::isSupported() const {
auto hmd = acquireOpenVrSystem(); return vr::VR_IsHmdPresent();
bool success = hmd != nullptr;
releaseOpenVrSystem();
return success;
} }
void ViveControllerManager::activate() { void ViveControllerManager::activate() {
@ -66,10 +63,12 @@ void ViveControllerManager::activate() {
} }
Q_ASSERT(_hmd); Q_ASSERT(_hmd);
// OpenVR provides 3d mesh representations of the controllers
// Disabled controller rendering code
/*
auto renderModels = vr::VRRenderModels(); auto renderModels = vr::VRRenderModels();
vr::RenderModel_t model; vr::RenderModel_t model;
/*
if (!_hmd->LoadRenderModel(CONTROLLER_MODEL_STRING, &model)) { if (!_hmd->LoadRenderModel(CONTROLLER_MODEL_STRING, &model)) {
qDebug() << QString("Unable to load render model %1\n").arg(CONTROLLER_MODEL_STRING); qDebug() << QString("Unable to load render model %1\n").arg(CONTROLLER_MODEL_STRING);
} else { } else {
@ -145,6 +144,7 @@ void ViveControllerManager::deactivate() {
void ViveControllerManager::updateRendering(RenderArgs* args, render::ScenePointer scene, render::PendingChanges pendingChanges) { void ViveControllerManager::updateRendering(RenderArgs* args, render::ScenePointer scene, render::PendingChanges pendingChanges) {
PerformanceTimer perfTimer("ViveControllerManager::updateRendering"); PerformanceTimer perfTimer("ViveControllerManager::updateRendering");
/*
if (_modelLoaded) { if (_modelLoaded) {
//auto controllerPayload = new render::Payload<ViveControllerManager>(this); //auto controllerPayload = new render::Payload<ViveControllerManager>(this);
//auto controllerPayloadPointer = ViveControllerManager::PayloadPointer(controllerPayload); //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) { void ViveControllerManager::renderHand(const controller::Pose& pose, gpu::Batch& batch, int sign) {
/*
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>(); auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
Transform transform(userInputMapper->getSensorToWorldMat()); Transform transform(userInputMapper->getSensorToWorldMat());
transform.postTranslate(pose.getTranslation() + pose.getRotation() * glm::vec3(0, 0, CONTROLLER_LENGTH_OFFSET)); 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); // mesh->getVertexBuffer()._stride);
batch.setIndexBuffer(gpu::UINT16, mesh->getIndexBuffer()._buffer, 0); batch.setIndexBuffer(gpu::UINT16, mesh->getIndexBuffer()._buffer, 0);
batch.drawIndexed(gpu::TRIANGLES, mesh->getNumIndices(), 0); batch.drawIndexed(gpu::TRIANGLES, mesh->getNumIndices(), 0);
*/
} }