From d0912c6063c974b9ff8c59532916fef68bcb0bda Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Fri, 29 Jul 2016 13:01:51 -0700 Subject: [PATCH] Threaded Oculus support --- plugins/oculus/CMakeLists.txt | 4 +- .../oculus/src/OculusBaseDisplayPlugin.cpp | 14 ++- plugins/oculus/src/OculusBaseDisplayPlugin.h | 1 + plugins/oculus/src/OculusDisplayPlugin.cpp | 108 ++++++++++++------ plugins/oculus/src/OculusDisplayPlugin.h | 7 +- plugins/oculus/src/OculusHelpers.cpp | 89 +-------------- plugins/oculus/src/OculusHelpers.h | 25 ---- 7 files changed, 92 insertions(+), 156 deletions(-) diff --git a/plugins/oculus/CMakeLists.txt b/plugins/oculus/CMakeLists.txt index 1edf902b02..d4d7a4e518 100644 --- a/plugins/oculus/CMakeLists.txt +++ b/plugins/oculus/CMakeLists.txt @@ -6,7 +6,6 @@ # See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html # -if (FALSE) if (WIN32) # we're using static GLEW, so define GLEW_STATIC @@ -14,7 +13,7 @@ if (WIN32) set(TARGET_NAME oculus) setup_hifi_plugin(Multimedia) - link_hifi_libraries(shared gl gpu controllers ui plugins ui-plugins display-plugins input-plugins audio-client networking) + link_hifi_libraries(shared gl gpu gpu-gl controllers ui plugins ui-plugins display-plugins input-plugins audio-client networking) include_hifi_library_headers(octree) @@ -25,4 +24,3 @@ if (WIN32) target_link_libraries(${TARGET_NAME} Winmm.lib) endif() -endif() \ No newline at end of file diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp index e26a48b89c..7690736a84 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "OculusHelpers.h" @@ -21,7 +22,7 @@ void OculusBaseDisplayPlugin::resetSensors() { bool OculusBaseDisplayPlugin::beginFrameRender(uint32_t frameIndex) { _currentRenderFrameInfo = FrameInfo(); - _currentRenderFrameInfo.sensorSampleTime = ovr_GetTimeInSeconds();; + _currentRenderFrameInfo.sensorSampleTime = ovr_GetTimeInSeconds(); _currentRenderFrameInfo.predictedDisplayTime = ovr_GetPredictedDisplayTime(_session, frameIndex); auto trackingState = ovr_GetTrackingState(_session, _currentRenderFrameInfo.predictedDisplayTime, ovrTrue); _currentRenderFrameInfo.renderPose = toGlm(trackingState.HeadPose.ThePose); @@ -40,7 +41,7 @@ bool OculusBaseDisplayPlugin::beginFrameRender(uint32_t frameIndex) { handPoses[hand] = glm::translate(glm::mat4(), correctedPose.translation) * glm::mat4_cast(correctedPose.rotation * HAND_TO_LASER_ROTATION); }); - withRenderThreadLock([&] { + withNonPresentThreadLock([&] { _uiModelTransform = DependencyManager::get()->getModelTransform(); _handPoses = handPoses; _frameInfos[frameIndex] = _currentRenderFrameInfo; @@ -112,3 +113,12 @@ void OculusBaseDisplayPlugin::internalDeactivate() { releaseOculusSession(); _session = nullptr; } + +void OculusBaseDisplayPlugin::updatePresentPose() { + //mat4 sensorResetMat; + //_currentPresentFrameInfo.sensorSampleTime = ovr_GetTimeInSeconds(); + //_currentPresentFrameInfo.predictedDisplayTime = ovr_GetPredictedDisplayTime(_session, _currentFrame->frameIndex); + //auto trackingState = ovr_GetTrackingState(_session, _currentRenderFrameInfo.predictedDisplayTime, ovrFalse); + //_currentPresentFrameInfo.presentPose = toGlm(trackingState.HeadPose.ThePose); + _currentPresentFrameInfo.presentPose = _currentPresentFrameInfo.renderPose; +} diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.h b/plugins/oculus/src/OculusBaseDisplayPlugin.h index 3e2c223908..503d8f0b90 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.h +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.h @@ -28,6 +28,7 @@ protected: void customizeContext() override; bool internalActivate() override; void internalDeactivate() override; + void updatePresentPose() override; protected: ovrSession _session { nullptr }; diff --git a/plugins/oculus/src/OculusDisplayPlugin.cpp b/plugins/oculus/src/OculusDisplayPlugin.cpp index 2b2ec5bdb0..24553ba494 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusDisplayPlugin.cpp @@ -13,6 +13,9 @@ #include #include +#include +#include +#include #include "OculusHelpers.h" @@ -43,67 +46,107 @@ void OculusDisplayPlugin::cycleDebugOutput() { void OculusDisplayPlugin::customizeContext() { Parent::customizeContext(); - _sceneFbo = SwapFboPtr(new SwapFramebufferWrapper(_session)); - _sceneFbo->Init(getRecommendedRenderSize()); + _outputFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_SRGBA_32, _renderTargetSize.x, _renderTargetSize.y)); + ovrTextureSwapChainDesc desc = { }; + desc.Type = ovrTexture_2D; + desc.ArraySize = 1; + desc.Width = _renderTargetSize.x; + desc.Height = _renderTargetSize.y; + desc.MipLevels = 1; + desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; + desc.SampleCount = 1; + desc.StaticImage = ovrFalse; + + ovrResult result = ovr_CreateTextureSwapChainGL(_session, &desc, &_textureSwapChain); + if (!OVR_SUCCESS(result)) { + logFatal("Failed to create swap textures"); + } + + int length = 0; + result = ovr_GetTextureSwapChainLength(_session, _textureSwapChain, &length); + if (!OVR_SUCCESS(result) || !length) { + qFatal("Unable to count swap chain textures"); + } + for (int i = 0; i < length; ++i) { + GLuint chainTexId; + ovr_GetTextureSwapChainBufferGL(_session, _textureSwapChain, i, &chainTexId); + glBindTexture(GL_TEXTURE_2D, chainTexId); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + glBindTexture(GL_TEXTURE_2D, 0); // We're rendering both eyes to the same texture, so only one of the // pointers is populated - _sceneLayer.ColorTexture[0] = _sceneFbo->color; + _sceneLayer.ColorTexture[0] = _textureSwapChain; // not needed since the structure was zeroed on init, but explicit _sceneLayer.ColorTexture[1] = nullptr; enableVsync(false); // Only enable mirroring if we know vsync is disabled _enablePreview = !isVsyncEnabled(); + } void OculusDisplayPlugin::uncustomizeContext() { - using namespace oglplus; - +#if 0 // Present a final black frame to the HMD _compositeFramebuffer->Bound(FramebufferTarget::Draw, [] { Context::ClearColor(0, 0, 0, 1); Context::Clear().ColorBuffer(); }); - hmdPresent(); - -#if (OVR_MAJOR_VERSION >= 6) - _sceneFbo.reset(); #endif + + ovr_DestroyTextureSwapChain(_session, _textureSwapChain); + _textureSwapChain = nullptr; Parent::uncustomizeContext(); } - -template -void blit(const SrcFbo& srcFbo, const DstFbo& dstFbo) { - using namespace oglplus; - srcFbo->Bound(FramebufferTarget::Read, [&] { - dstFbo->Bound(FramebufferTarget::Draw, [&] { - Context::BlitFramebuffer( - 0, 0, srcFbo->size.x, srcFbo->size.y, - 0, 0, dstFbo->size.x, dstFbo->size.y, - BufferSelectBit::ColorBuffer, BlitFilter::Linear); - }); - }); -} - void OculusDisplayPlugin::hmdPresent() { - PROFILE_RANGE_EX(__FUNCTION__, 0xff00ff00, (uint64_t)_currentPresentFrameIndex) + PROFILE_RANGE_EX(__FUNCTION__, 0xff00ff00, (uint64_t)_currentFrame->frameIndex) - if (!_currentSceneTexture) { - return; + // Manually bind the texture to the FBO + auto& glBackend = dynamic_cast(*_backend); + auto fbo = glBackend.getFramebufferID(_outputFramebuffer); + { + int curIndex; + ovr_GetTextureSwapChainCurrentIndex(_session, _textureSwapChain, &curIndex); + GLuint curTexId; + ovr_GetTextureSwapChainBufferGL(_session, _textureSwapChain, curIndex, &curTexId); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, curTexId, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); } - blit(_compositeFramebuffer, _sceneFbo); - _sceneFbo->Commit(); { + gpu::Batch batch; + batch.enableStereo(false); + auto source = _currentFrame->framebuffer; + auto sourceRect = ivec4(ivec2(0), source->getSize()); + auto dest = _outputFramebuffer; + auto destRect = ivec4(ivec2(0), dest->getSize()); + batch.blit(source, sourceRect, dest, destRect); + _backend->render(batch); + } + + { + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + } + + { + auto result = ovr_CommitTextureSwapChain(_session, _textureSwapChain); + Q_ASSERT(OVR_SUCCESS(result)); _sceneLayer.SensorSampleTime = _currentPresentFrameInfo.sensorSampleTime; _sceneLayer.RenderPose[ovrEyeType::ovrEye_Left] = ovrPoseFromGlm(_currentPresentFrameInfo.renderPose); _sceneLayer.RenderPose[ovrEyeType::ovrEye_Right] = ovrPoseFromGlm(_currentPresentFrameInfo.renderPose); ovrLayerHeader* layers = &_sceneLayer.Header; - ovrResult result = ovr_SubmitFrame(_session, _currentPresentFrameIndex, &_viewScaleDesc, &layers, 1); + result = ovr_SubmitFrame(_session, _currentFrame->frameIndex, &_viewScaleDesc, &layers, 1); if (!OVR_SUCCESS(result)) { logWarning("Failed to present"); } @@ -112,11 +155,11 @@ void OculusDisplayPlugin::hmdPresent() { bool OculusDisplayPlugin::isHmdMounted() const { ovrSessionStatus status; - return (OVR_SUCCESS(ovr_GetSessionStatus(_session, &status)) && + return (OVR_SUCCESS(ovr_GetSessionStatus(_session, &status)) && (ovrFalse != status.HmdMounted)); } -QString OculusDisplayPlugin::getPreferredAudioInDevice() const { +QString OculusDisplayPlugin::getPreferredAudioInDevice() const { WCHAR buffer[OVR_AUDIO_MAX_DEVICE_STR_SIZE]; if (!OVR_SUCCESS(ovr_GetAudioDeviceInGuidStr(buffer))) { return QString(); @@ -124,11 +167,10 @@ QString OculusDisplayPlugin::getPreferredAudioInDevice() const { return AudioClient::friendlyNameForAudioDevice(buffer); } -QString OculusDisplayPlugin::getPreferredAudioOutDevice() const { +QString OculusDisplayPlugin::getPreferredAudioOutDevice() const { WCHAR buffer[OVR_AUDIO_MAX_DEVICE_STR_SIZE]; if (!OVR_SUCCESS(ovr_GetAudioDeviceOutGuidStr(buffer))) { return QString(); } return AudioClient::friendlyNameForAudioDevice(buffer); } - diff --git a/plugins/oculus/src/OculusDisplayPlugin.h b/plugins/oculus/src/OculusDisplayPlugin.h index ed6e0d13ea..bcd8f5d8ab 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.h +++ b/plugins/oculus/src/OculusDisplayPlugin.h @@ -9,9 +9,6 @@ #include "OculusBaseDisplayPlugin.h" -struct SwapFramebufferWrapper; -using SwapFboPtr = QSharedPointer; - class OculusDisplayPlugin : public OculusBaseDisplayPlugin { using Parent = OculusBaseDisplayPlugin; public: @@ -34,7 +31,7 @@ private: static const QString NAME; bool _enablePreview { false }; bool _monoPreview { true }; - - SwapFboPtr _sceneFbo; + ovrTextureSwapChain _textureSwapChain; + gpu::FramebufferPointer _outputFramebuffer; }; diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index 49c14c8d66..80390fd538 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -18,6 +18,7 @@ #include #include +#include using Mutex = std::mutex; using Lock = std::unique_lock; @@ -116,94 +117,6 @@ void releaseOculusSession() { } -// A wrapper for constructing and using a swap texture set, -// where each frame you draw to a texture via the FBO, -// then submit it and increment to the next texture. -// The Oculus SDK manages the creation and destruction of -// the textures - -SwapFramebufferWrapper::SwapFramebufferWrapper(const ovrSession& session) - : _session(session) { - color = nullptr; - depth = nullptr; -} - -SwapFramebufferWrapper::~SwapFramebufferWrapper() { - destroyColor(); -} - -void SwapFramebufferWrapper::Commit() { - auto result = ovr_CommitTextureSwapChain(_session, color); - Q_ASSERT(OVR_SUCCESS(result)); -} - -void SwapFramebufferWrapper::Resize(const uvec2 & size) { - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oglplus::GetName(fbo)); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - this->size = size; - initColor(); - initDone(); -} - -void SwapFramebufferWrapper::destroyColor() { - if (color) { - ovr_DestroyTextureSwapChain(_session, color); - color = nullptr; - } -} - -void SwapFramebufferWrapper::initColor() { - destroyColor(); - - ovrTextureSwapChainDesc desc = {}; - desc.Type = ovrTexture_2D; - desc.ArraySize = 1; - desc.Width = size.x; - desc.Height = size.y; - desc.MipLevels = 1; - desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; - desc.SampleCount = 1; - desc.StaticImage = ovrFalse; - - ovrResult result = ovr_CreateTextureSwapChainGL(_session, &desc, &color); - if (!OVR_SUCCESS(result)) { - logFatal("Failed to create swap textures"); - } - - int length = 0; - result = ovr_GetTextureSwapChainLength(_session, color, &length); - if (!OVR_SUCCESS(result) || !length) { - qFatal("Unable to count swap chain textures"); - } - for (int i = 0; i < length; ++i) { - GLuint chainTexId; - ovr_GetTextureSwapChainBufferGL(_session, color, i, &chainTexId); - glBindTexture(GL_TEXTURE_2D, chainTexId); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - glBindTexture(GL_TEXTURE_2D, 0); -} - -void SwapFramebufferWrapper::initDone() { -} - -void SwapFramebufferWrapper::onBind(oglplus::Framebuffer::Target target) { - int curIndex; - ovr_GetTextureSwapChainCurrentIndex(_session, color, &curIndex); - GLuint curTexId; - ovr_GetTextureSwapChainBufferGL(_session, color, curIndex, &curTexId); - glFramebufferTexture2D(toEnum(target), GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, curTexId, 0); -} - -void SwapFramebufferWrapper::onUnbind(oglplus::Framebuffer::Target target) { - glFramebufferTexture2D(toEnum(target), GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); -} - - controller::Pose ovrControllerPoseToHandPose( ovrHandType hand, const ovrPoseStatef& handPose) { diff --git a/plugins/oculus/src/OculusHelpers.h b/plugins/oculus/src/OculusHelpers.h index 66cdccf15a..ba0547ae0a 100644 --- a/plugins/oculus/src/OculusHelpers.h +++ b/plugins/oculus/src/OculusHelpers.h @@ -12,7 +12,6 @@ #include #include -#include #include void logWarning(const char* what); @@ -106,30 +105,6 @@ inline ovrPosef ovrPoseFromGlm(const glm::mat4 & m) { return result; } - -// A wrapper for constructing and using a swap texture set, -// where each frame you draw to a texture via the FBO, -// then submit it and increment to the next texture. -// The Oculus SDK manages the creation and destruction of -// the textures -struct SwapFramebufferWrapper : public FramebufferWrapper { - SwapFramebufferWrapper(const ovrSession& session); - ~SwapFramebufferWrapper(); - void Commit(); - void Resize(const uvec2 & size); -protected: - void initColor() override final; - void initDepth() override final {} - void initDone() override final; - void onBind(oglplus::Framebuffer::Target target) override final; - void onUnbind(oglplus::Framebuffer::Target target) override final; - - void destroyColor(); - -private: - ovrSession _session; -}; - controller::Pose ovrControllerPoseToHandPose( ovrHandType hand, const ovrPoseStatef& handPose);