From b9ace94ff1fa8e0b86603c10afe3f20eb050d7ae Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 30 Nov 2015 09:35:18 -0800 Subject: [PATCH] Prototyping threaded present --- interface/resources/qml/Stats.qml | 7 +- interface/src/Application.cpp | 83 +++--- interface/src/Application.h | 6 + interface/src/GLCanvas.cpp | 21 -- interface/src/GLCanvas.h | 2 - interface/src/PluginContainerProxy.cpp | 87 ++++-- interface/src/PluginContainerProxy.h | 7 +- interface/src/avatar/AvatarUpdate.cpp | 3 +- interface/src/avatar/MyAvatar.cpp | 2 +- interface/src/ui/ApplicationCompositor.cpp | 2 +- interface/src/ui/Stats.cpp | 8 +- interface/src/ui/Stats.h | 6 +- .../Basic2DWindowOpenGLDisplayPlugin.cpp | 80 +++--- .../Basic2DWindowOpenGLDisplayPlugin.h | 9 +- .../src/display-plugins/DisplayPlugin.cpp | 30 +- .../src/display-plugins/NullDisplayPlugin.cpp | 13 +- .../src/display-plugins/NullDisplayPlugin.h | 6 +- .../display-plugins/OpenGLDisplayPlugin.cpp | 258 +++++++++++++++--- .../src/display-plugins/OpenGLDisplayPlugin.h | 66 +++-- .../WindowOpenGLDisplayPlugin.cpp | 28 +- .../WindowOpenGLDisplayPlugin.h | 12 +- .../openvr/OpenVrDisplayPlugin.cpp | 40 +-- .../openvr/OpenVrDisplayPlugin.h | 6 +- .../stereo/InterleavedStereoDisplayPlugin.cpp | 8 +- .../stereo/InterleavedStereoDisplayPlugin.h | 3 +- libraries/gl/src/gl/GLEscrow.h | 24 +- libraries/plugins/src/plugins/DisplayPlugin.h | 30 +- .../plugins/src/plugins/PluginContainer.h | 11 +- .../oculus/src/OculusBaseDisplayPlugin.cpp | 28 +- plugins/oculus/src/OculusBaseDisplayPlugin.h | 8 +- .../oculus/src/OculusDebugDisplayPlugin.cpp | 10 - plugins/oculus/src/OculusDebugDisplayPlugin.h | 3 - plugins/oculus/src/OculusDisplayPlugin.cpp | 60 ++-- plugins/oculus/src/OculusDisplayPlugin.h | 11 +- plugins/oculus/src/OculusHelpers.cpp | 1 - .../src/OculusLegacyDisplayPlugin.h | 1 - tests/controllers/src/main.cpp | 7 +- 37 files changed, 600 insertions(+), 387 deletions(-) diff --git a/interface/resources/qml/Stats.qml b/interface/resources/qml/Stats.qml index 84381cc754..56d4f9c14b 100644 --- a/interface/resources/qml/Stats.qml +++ b/interface/resources/qml/Stats.qml @@ -45,7 +45,12 @@ Item { Text { color: root.fontColor; font.pixelSize: root.fontSize - text: "Framerate: " + root.framerate + text: "Render Rate: " + root.renderrate + } + Text { + color: root.fontColor; + font.pixelSize: root.fontSize + text: "Present Rate: " + root.presentrate } Text { color: root.fontColor; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c552feb51b..581fdbec5a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -150,6 +150,8 @@ #include "InterfaceParentFinder.h" +#include +#include // ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU // FIXME seems to be broken. @@ -1089,6 +1091,7 @@ void Application::paintGL() { // update fps once a second if (now - _lastFramesPerSecondUpdate > USECS_PER_SECOND) { _fps = _framesPerSecond.getAverage(); + qDebug() << QString::number(_fps, 'g', 4); _lastFramesPerSecondUpdate = now; } @@ -1136,7 +1139,7 @@ void Application::paintGL() { _lastInstantaneousFps = instantaneousFps; auto displayPlugin = getActiveDisplayPlugin(); - displayPlugin->preRender(); + // FIXME not needed anymore? _offscreenContext->makeCurrent(); // update the avatar with a fresh HMD pose @@ -1304,6 +1307,13 @@ void Application::paintGL() { auto baseProjection = renderArgs._viewFrustum->getProjection(); auto hmdInterface = DependencyManager::get(); float IPDScale = hmdInterface->getIPDScale(); + + // Tell the plugin what pose we're using to render. In this case we're just using the + // unmodified head pose because the only plugin that cares (the Oculus plugin) uses it + // for rotational timewarp. If we move to support positonal timewarp, we need to + // ensure this contains the full pose composed with the eye offsets. + mat4 headPose = displayPlugin->getHeadPose(_frameCount); + // FIXME we probably don't need to set the projection matrix every frame, // only when the display plugin changes (or in non-HMD modes when the user // changes the FOV manually, which right now I don't think they can. @@ -1319,12 +1329,7 @@ void Application::paintGL() { mat4 eyeOffsetTransform = glm::translate(mat4(), eyeOffset * -1.0f * IPDScale); eyeOffsets[eye] = eyeOffsetTransform; - // Tell the plugin what pose we're using to render. In this case we're just using the - // unmodified head pose because the only plugin that cares (the Oculus plugin) uses it - // for rotational timewarp. If we move to support positonal timewarp, we need to - // ensure this contains the full pose composed with the eye offsets. - mat4 headPose = displayPlugin->getHeadPose(); - displayPlugin->setEyeRenderPose(eye, headPose); + displayPlugin->setEyeRenderPose(_frameCount, eye, headPose); eyeProjections[eye] = displayPlugin->getProjection(eye, baseProjection); }); @@ -1367,44 +1372,35 @@ void Application::paintGL() { { PROFILE_RANGE(__FUNCTION__ "/pluginOutput"); PerformanceTimer perfTimer("pluginOutput"); - auto primaryFbo = framebufferCache->getPrimaryFramebuffer(); - GLuint finalTexture = gpu::GLBackend::getTextureID(primaryFbo->getRenderBuffer(0)); - // Ensure the rendering context commands are completed when rendering - GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - // Ensure the sync object is flushed to the driver thread before releasing the context - // CRITICAL for the mac driver apparently. - glFlush(); - _offscreenContext->doneCurrent(); - - // Switches to the display plugin context - displayPlugin->preDisplay(); - // Ensure all operations from the previous context are complete before we try to read the fbo - glWaitSync(sync, 0, GL_TIMEOUT_IGNORED); - glDeleteSync(sync); uint64_t displayStart = usecTimestampNow(); + auto primaryFramebuffer = framebufferCache->getPrimaryFramebuffer(); + auto scratchFramebuffer = framebufferCache->getFramebuffer(); + gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) { + gpu::Vec4i rect; + rect.z = size.width(); + rect.w = size.height(); + batch.setFramebuffer(scratchFramebuffer); + batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(0.0f, 0.0f, 0.0f, 0.0f)); + batch.blit(primaryFramebuffer, rect, scratchFramebuffer, rect); + batch.setFramebuffer(nullptr); + }); + auto finalTexturePointer = scratchFramebuffer->getRenderBuffer(0); + GLuint finalTexture = gpu::GLBackend::getTextureID(finalTexturePointer); - { - PROFILE_RANGE(__FUNCTION__ "/pluginDisplay"); - PerformanceTimer perfTimer("pluginDisplay"); - displayPlugin->display(finalTexture, toGlm(size)); - } + Q_ASSERT(0 != finalTexture); + Q_ASSERT(!_lockedFramebufferMap.contains(finalTexture)); + _lockedFramebufferMap[finalTexture] = scratchFramebuffer; + Q_ASSERT(QOpenGLContext::currentContext() == _offscreenContext->getContext()); + displayPlugin->submitSceneTexture(_frameCount, finalTexture, toGlm(size)); + Q_ASSERT(QOpenGLContext::currentContext() == _offscreenContext->getContext()); - { - PROFILE_RANGE(__FUNCTION__ "/bufferSwap"); - PerformanceTimer perfTimer("bufferSwap"); - displayPlugin->finishFrame(); - } uint64_t displayEnd = usecTimestampNow(); const float displayPeriodUsec = (float)(displayEnd - displayStart); // usecs _lastPaintWait = displayPeriodUsec / (float)USECS_PER_SECOND; - } { - PerformanceTimer perfTimer("makeCurrent"); - _offscreenContext->makeCurrent(); Stats::getInstance()->setRenderDetails(renderArgs._details); - // Reset the gpu::Context Stages // Back to the default framebuffer; gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) { @@ -2612,7 +2608,7 @@ void Application::updateMyAvatarLookAtPosition() { lookAtPosition.x = -lookAtPosition.x; } if (isHMD) { - glm::mat4 headPose = getActiveDisplayPlugin()->getHeadPose(); + glm::mat4 headPose = getActiveDisplayPlugin()->getHeadPose(_frameCount); glm::quat hmdRotation = glm::quat_cast(headPose); lookAtSpot = _myCamera.getPosition() + myAvatar->getOrientation() * (hmdRotation * lookAtPosition); } else { @@ -4503,6 +4499,7 @@ void Application::toggleLogDialog() { } void Application::takeSnapshot() { +#if 0 QMediaPlayer* player = new QMediaPlayer(); QFileInfo inf = QFileInfo(PathUtils::resourcesPath() + "sounds/snap.wav"); player->setMedia(QUrl::fromLocalFile(inf.absoluteFilePath())); @@ -4519,7 +4516,7 @@ void Application::takeSnapshot() { _snapshotShareDialog = new SnapshotShareDialog(fileName, _glWidget); } _snapshotShareDialog->show(); - +#endif } float Application::getRenderResolutionScale() const { @@ -4702,10 +4699,6 @@ const DisplayPlugin* Application::getActiveDisplayPlugin() const { return ((Application*)this)->getActiveDisplayPlugin(); } -bool _activatingDisplayPlugin{ false }; -QVector> _currentDisplayPluginActions; -QVector> _currentInputPluginActions; - static void addDisplayPluginToMenu(DisplayPluginPointer displayPlugin, bool active = false) { auto menu = Menu::getInstance(); QString name = displayPlugin->getName(); @@ -4735,9 +4728,9 @@ void Application::updateDisplayMode() { bool first = true; foreach(auto displayPlugin, displayPlugins) { addDisplayPluginToMenu(displayPlugin, first); - QObject::connect(displayPlugin.get(), &DisplayPlugin::requestRender, [this] { - paintGL(); - }); + QObject::connect(displayPlugin.get(), &DisplayPlugin::requestRender, + this, &Application::paintGL, Qt::QueuedConnection); + QObject::connect(displayPlugin.get(), &DisplayPlugin::recommendedFramebufferSizeChanged, [this](const QSize & size) { resizeGL(); }); @@ -4917,7 +4910,7 @@ mat4 Application::getEyeOffset(int eye) const { mat4 Application::getHMDSensorPose() const { if (isHMDMode()) { - return getActiveDisplayPlugin()->getHeadPose(); + return getActiveDisplayPlugin()->getHeadPose(_frameCount); } return mat4(); } diff --git a/interface/src/Application.h b/interface/src/Application.h index e2445f7f22..1af252de95 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -158,6 +158,7 @@ public: bool isForeground() const { return _isForeground; } + uint32_t getFrameCount() { return _frameCount; } float getFps() const { return _fps; } float const HMD_TARGET_FRAME_RATE = 75.0f; float const DESKTOP_TARGET_FRAME_RATE = 60.0f; @@ -425,6 +426,11 @@ private: DisplayPluginPointer _displayPlugin; InputPluginList _activeInputPlugins; + bool _activatingDisplayPlugin { false }; + QVector> _currentDisplayPluginActions; + QVector> _currentInputPluginActions; + QMap _lockedFramebufferMap; + MainWindow* _window; ToolWindow* _toolWindow; diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index 0b4c6dde3d..ec96f7c5d4 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -13,27 +13,6 @@ #include "Application.h" #include "GLCanvas.h" -#include - -#include "MainWindow.h" -#include "Menu.h" - -void GLCanvas::paintGL() { - PROFILE_RANGE(__FUNCTION__); - - // FIXME - I'm not sure why this still remains, it appears as if this GLCanvas gets a single paintGL call near - // the beginning of the application starting up. I'm not sure if we really need to call Application::paintGL() - // in this case, since the display plugins eventually handle all the painting - bool isThrottleFPSEnabled = Menu::getInstance()->isOptionChecked(MenuOption::ThrottleFPSIfNotFocus); - if (!qApp->getWindow()->isMinimized() || !isThrottleFPSEnabled) { - qApp->paintGL(); - } -} - -void GLCanvas::resizeGL(int width, int height) { - qApp->resizeGL(); -} - bool GLCanvas::event(QEvent* event) { if (QEvent::Paint == event->type() && qApp->isAboutToQuit()) { return true; diff --git a/interface/src/GLCanvas.h b/interface/src/GLCanvas.h index 0442159eeb..f707046c7c 100644 --- a/interface/src/GLCanvas.h +++ b/interface/src/GLCanvas.h @@ -18,8 +18,6 @@ class GLCanvas : public GLWidget { Q_OBJECT protected: - virtual void paintGL() override; - virtual void resizeGL(int width, int height) override; virtual bool event(QEvent* event) override; }; diff --git a/interface/src/PluginContainerProxy.cpp b/interface/src/PluginContainerProxy.cpp index 2e5c883897..8774eecd77 100644 --- a/interface/src/PluginContainerProxy.cpp +++ b/interface/src/PluginContainerProxy.cpp @@ -1,17 +1,23 @@ #include "PluginContainerProxy.h" -#include -#include +#include +#include #include #include #include +#include +#include +#include #include "Application.h" #include "MainWindow.h" #include "GLCanvas.h" #include "ui/DialogsManager.h" +#include +#include + PluginContainerProxy::PluginContainerProxy() { } @@ -36,30 +42,31 @@ extern QVector> _currentInputPluginActions; std::map _exclusiveGroups; QAction* PluginContainerProxy::addMenuItem(const QString& path, const QString& name, std::function onClicked, bool checkable, bool checked, const QString& groupName) { - auto menu = Menu::getInstance(); - MenuWrapper* parentItem = menu->getMenu(path); - QAction* action = menu->addActionToQMenuAndActionHash(parentItem, name); - if (!groupName.isEmpty()) { - QActionGroup* group{ nullptr }; - if (!_exclusiveGroups.count(groupName)) { - group = _exclusiveGroups[groupName] = new QActionGroup(menu); - group->setExclusive(true); - } else { - group = _exclusiveGroups[groupName]; - } - group->addAction(action); - } - connect(action, &QAction::triggered, [=] { - onClicked(action->isChecked()); - }); - action->setCheckable(checkable); - action->setChecked(checked); - if (_activatingDisplayPlugin) { - _currentDisplayPluginActions.push_back({ path, name }); - } else { - _currentInputPluginActions.push_back({ path, name }); - } - return action; + //auto menu = Menu::getInstance(); + //MenuWrapper* parentItem = menu->getMenu(path); + //QAction* action = menu->addActionToQMenuAndActionHash(parentItem, name); + //if (!groupName.isEmpty()) { + // QActionGroup* group{ nullptr }; + // if (!_exclusiveGroups.count(groupName)) { + // group = _exclusiveGroups[groupName] = new QActionGroup(menu); + // group->setExclusive(true); + // } else { + // group = _exclusiveGroups[groupName]; + // } + // group->addAction(action); + //} + //connect(action, &QAction::triggered, [=] { + // onClicked(action->isChecked()); + //}); + //action->setCheckable(checkable); + //action->setChecked(checked); + //if (_activatingDisplayPlugin) { + // _currentDisplayPluginActions.push_back({ path, name }); + //} else { + // _currentInputPluginActions.push_back({ path, name }); + //} + //return action; + return nullptr; } void PluginContainerProxy::removeMenuItem(const QString& menuName, const QString& menuItem) { @@ -150,10 +157,36 @@ void PluginContainerProxy::showDisplayPluginsTools() { DependencyManager::get()->hmdTools(true); } -QGLWidget* PluginContainerProxy::getPrimarySurface() { +QGLWidget* PluginContainerProxy::getPrimaryWidget() { return qApp->_glWidget; } +QWindow* PluginContainerProxy::getPrimaryWindow() { + return qApp->_glWidget->windowHandle(); +} + +QOpenGLContext* PluginContainerProxy::getPrimaryContext() { + return qApp->_glWidget->context()->contextHandle(); +} + const DisplayPlugin* PluginContainerProxy::getActiveDisplayPlugin() const { return qApp->getActiveDisplayPlugin(); } + +bool PluginContainerProxy::makeRenderingContextCurrent() { + return qApp->_offscreenContext->makeCurrent(); +} + +void PluginContainerProxy::releaseSceneTexture(uint32_t texture) { + Q_ASSERT(QThread::currentThread() == qApp->thread()); + auto& framebufferMap = qApp->_lockedFramebufferMap; + Q_ASSERT(framebufferMap.contains(texture)); + auto framebufferPointer = framebufferMap[texture]; + framebufferMap.remove(texture); + auto framebufferCache = DependencyManager::get(); + framebufferCache->releaseFramebuffer(framebufferPointer); +} + +void PluginContainerProxy::releaseOverlayTexture(uint32_t texture) { + +} diff --git a/interface/src/PluginContainerProxy.h b/interface/src/PluginContainerProxy.h index 79f8287b66..5cc1cc8583 100644 --- a/interface/src/PluginContainerProxy.h +++ b/interface/src/PluginContainerProxy.h @@ -22,7 +22,12 @@ class PluginContainerProxy : public QObject, PluginContainer { virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) override; virtual void showDisplayPluginsTools() override; virtual void requestReset() override; - virtual QGLWidget* getPrimarySurface() override; + virtual bool makeRenderingContextCurrent() override; + virtual void releaseSceneTexture(uint32_t texture) override; + virtual void releaseOverlayTexture(uint32_t texture) override; + virtual QGLWidget* getPrimaryWidget() override; + virtual QWindow* getPrimaryWindow() override; + virtual QOpenGLContext* getPrimaryContext() override; virtual bool isForeground() override; virtual const DisplayPlugin* getActiveDisplayPlugin() const override; diff --git a/interface/src/avatar/AvatarUpdate.cpp b/interface/src/avatar/AvatarUpdate.cpp index 52fa568879..99e5d2acaa 100644 --- a/interface/src/avatar/AvatarUpdate.cpp +++ b/interface/src/avatar/AvatarUpdate.cpp @@ -30,7 +30,8 @@ void AvatarUpdate::synchronousProcess() { // Keep our own updated value, so that our asynchronous code can consult it. _isHMDMode = qApp->isHMDMode(); - _headPose = qApp->getActiveDisplayPlugin()->getHeadPose(); + auto frameCount = qApp->getFrameCount(); + _headPose = qApp->getActiveDisplayPlugin()->getHeadPose(frameCount); if (_updateBillboard) { DependencyManager::get()->getMyAvatar()->doUpdateBillboard(); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5f43b834ec..1a098ec5f6 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1200,7 +1200,7 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, fl if (qApp->isHMDMode()) { glm::vec3 cameraPosition = qApp->getCamera()->getPosition(); - glm::mat4 headPose = qApp->getActiveDisplayPlugin()->getHeadPose(); + glm::mat4 headPose = qApp->getActiveDisplayPlugin()->getHeadPose(qApp->getFrameCount()); glm::mat4 leftEyePose = qApp->getActiveDisplayPlugin()->getEyeToHeadTransform(Eye::Left); leftEyePose = leftEyePose * headPose; glm::vec3 leftEyePosition = extractTranslation(leftEyePose); diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index eb43b9d864..4cee190a47 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -287,7 +287,7 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int mat4 camMat; _cameraBaseTransform.getMatrix(camMat); auto displayPlugin = qApp->getActiveDisplayPlugin(); - auto headPose = displayPlugin->getHeadPose(); + auto headPose = displayPlugin->getHeadPose(qApp->getFrameCount()); auto eyeToHead = displayPlugin->getEyeToHeadTransform((Eye)eye); camMat = (headPose * eyeToHead) * camMat; batch.setViewportTransform(renderArgs->_viewport); diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 12692698e7..358dc49bdb 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "BandwidthRecorder.h" #include "Menu.h" @@ -118,7 +119,12 @@ void Stats::updateStats(bool force) { STAT_UPDATE(avatarRenderableCount, avatarManager->getNumberInRenderRange()); STAT_UPDATE(avatarRenderDistance, (int) round(avatarManager->getRenderDistance())); // deliberately truncating STAT_UPDATE(serverCount, nodeList->size()); - STAT_UPDATE(framerate, (int)qApp->getFps()); + STAT_UPDATE(renderrate, (int)qApp->getFps()); + if (qApp->getActiveDisplayPlugin()) { + STAT_UPDATE(presentrate, (int)qApp->getActiveDisplayPlugin()->presentRate()); + } else { + STAT_UPDATE(presentrate, -1); + } STAT_UPDATE(simrate, (int)qApp->getAverageSimsPerSecond()); STAT_UPDATE(avatarSimrate, (int)qApp->getAvatarSimrate()); diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h index d1c0dd19d7..eb28883001 100644 --- a/interface/src/ui/Stats.h +++ b/interface/src/ui/Stats.h @@ -32,7 +32,8 @@ class Stats : public QQuickItem { Q_PROPERTY(float audioPacketlossDownstream READ getAudioPacketLossDownstream) STATS_PROPERTY(int, serverCount, 0) - STATS_PROPERTY(int, framerate, 0) + STATS_PROPERTY(int, renderrate, 0) + STATS_PROPERTY(int, presentrate, 0) STATS_PROPERTY(int, simrate, 0) STATS_PROPERTY(int, avatarSimrate, 0) STATS_PROPERTY(int, avatarCount, 0) @@ -115,7 +116,8 @@ signals: void expandedChanged(); void timingExpandedChanged(); void serverCountChanged(); - void framerateChanged(); + void renderrateChanged(); + void presentrateChanged(); void simrateChanged(); void avatarSimrateChanged(); void avatarCountChanged(); diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp index 9366ec4403..36216f8912 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp @@ -30,44 +30,41 @@ const QString& Basic2DWindowOpenGLDisplayPlugin::getName() const { return NAME; } -std::vector _framerateActions; -QAction* _vsyncAction{ nullptr }; - void Basic2DWindowOpenGLDisplayPlugin::activate() { - _framerateActions.clear(); - _container->addMenuItem(MENU_PATH(), FULLSCREEN, - [this](bool clicked) { - if (clicked) { - _container->setFullscreen(getFullscreenTarget()); - } else { - _container->unsetFullscreen(); - } - }, true, false); - _container->addMenu(FRAMERATE); - _framerateActions.push_back( - _container->addMenuItem(FRAMERATE, FRAMERATE_UNLIMITED, - [this](bool) { updateFramerate(); }, true, true, FRAMERATE)); - _framerateActions.push_back( - _container->addMenuItem(FRAMERATE, FRAMERATE_60, - [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); - _framerateActions.push_back( - _container->addMenuItem(FRAMERATE, FRAMERATE_50, - [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); - _framerateActions.push_back( - _container->addMenuItem(FRAMERATE, FRAMERATE_40, - [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); - _framerateActions.push_back( - _container->addMenuItem(FRAMERATE, FRAMERATE_30, - [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); + //_framerateActions.clear(); + //_container->addMenuItem(MENU_PATH(), FULLSCREEN, + // [this](bool clicked) { + // if (clicked) { + // _container->setFullscreen(getFullscreenTarget()); + // } else { + // _container->unsetFullscreen(); + // } + // }, true, false); + //_container->addMenu(FRAMERATE); + //_framerateActions.push_back( + // _container->addMenuItem(FRAMERATE, FRAMERATE_UNLIMITED, + // [this](bool) { updateFramerate(); }, true, true, FRAMERATE)); + //_framerateActions.push_back( + // _container->addMenuItem(FRAMERATE, FRAMERATE_60, + // [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); + //_framerateActions.push_back( + // _container->addMenuItem(FRAMERATE, FRAMERATE_50, + // [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); + //_framerateActions.push_back( + // _container->addMenuItem(FRAMERATE, FRAMERATE_40, + // [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); + //_framerateActions.push_back( + // _container->addMenuItem(FRAMERATE, FRAMERATE_30, + // [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); WindowOpenGLDisplayPlugin::activate(); - // Vsync detection happens in the parent class activate, so we need to check after that - if (_vsyncSupported) { - _vsyncAction = _container->addMenuItem(MENU_PATH(), VSYNC_ON, [this](bool) {}, true, true); - } else { - _vsyncAction = nullptr; - } + //// Vsync detection happens in the parent class activate, so we need to check after that + //if (_vsyncSupported) { + // _vsyncAction = _container->addMenuItem(MENU_PATH(), VSYNC_ON, [this](bool) {}, true, true); + //} else { + // _vsyncAction = nullptr; + //} updateFramerate(); } @@ -76,19 +73,18 @@ void Basic2DWindowOpenGLDisplayPlugin::deactivate() { WindowOpenGLDisplayPlugin::deactivate(); } -void Basic2DWindowOpenGLDisplayPlugin::display(GLuint sceneTexture, const glm::uvec2& sceneSize) { +void Basic2DWindowOpenGLDisplayPlugin::submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) { if (_vsyncAction) { - bool wantVsync = _vsyncAction->isChecked(); - bool vsyncEnabed = isVsyncEnabled(); - if (vsyncEnabed ^ wantVsync) { - enableVsync(wantVsync); - } + _wantVsync = _vsyncAction->isChecked(); + //bool vsyncEnabed = isVsyncEnabled(); + //if (vsyncEnabed ^ wantVsync) { + // enableVsync(wantVsync); + //} } - WindowOpenGLDisplayPlugin::display(sceneTexture, sceneSize); + WindowOpenGLDisplayPlugin::submitSceneTexture(frameIndex, sceneTexture, sceneSize); } - int Basic2DWindowOpenGLDisplayPlugin::getDesiredInterval() const { static const int THROTTLED_PAINT_TIMER_DELAY_MS = MSECS_PER_SECOND / 15; static const int ULIMIITED_PAINT_TIMER_DELAY_MS = 1; diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h index f4655ab79f..80aebf9efc 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h @@ -10,6 +10,8 @@ #include "WindowOpenGLDisplayPlugin.h" class QScreen; +class QAction; + class Basic2DWindowOpenGLDisplayPlugin : public WindowOpenGLDisplayPlugin { Q_OBJECT @@ -19,7 +21,7 @@ public: virtual void activate() override; virtual void deactivate() override; - virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize) override; + virtual void submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) override; virtual bool isThrottled() const override; @@ -31,6 +33,9 @@ private: void updateFramerate(); static const QString NAME; QScreen* getFullscreenTarget(); - uint32_t _framerateTarget{ 0 }; + std::vector _framerateActions; + QAction* _vsyncAction { nullptr }; + uint32_t _framerateTarget { 0 }; int _fullscreenTarget{ -1 }; + bool _wantVsync { true }; }; diff --git a/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp index 8155d69826..85e832abdd 100644 --- a/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp @@ -25,22 +25,22 @@ const QString& DisplayPlugin::MENU_PATH() { DisplayPluginList getDisplayPlugins() { DisplayPlugin* PLUGIN_POOL[] = { new Basic2DWindowOpenGLDisplayPlugin(), -#ifdef DEBUG new NullDisplayPlugin(), -#endif - - // Stereo modes - - // SBS left/right - new SideBySideStereoDisplayPlugin(), - // Interleaved left/right - new InterleavedStereoDisplayPlugin(), - - // HMDs -#ifdef Q_OS_WIN - // SteamVR SDK - new OpenVrDisplayPlugin(), -#endif +//#ifdef DEBUG +//#endif +// +// // Stereo modes +// +// // SBS left/right +// new SideBySideStereoDisplayPlugin(), +// // Interleaved left/right +// new InterleavedStereoDisplayPlugin(), +// +// // HMDs +//#ifdef Q_OS_WIN +// // SteamVR SDK +// new OpenVrDisplayPlugin(), +//#endif nullptr }; diff --git a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp index ce512962ff..b0f02b1149 100644 --- a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp @@ -9,6 +9,7 @@ // #include "NullDisplayPlugin.h" +#include const QString NullDisplayPlugin::NAME("NullDisplayPlugin"); const QString & NullDisplayPlugin::getName() const { @@ -23,8 +24,12 @@ bool NullDisplayPlugin::hasFocus() const { return false; } -void NullDisplayPlugin::preRender() {} -void NullDisplayPlugin::preDisplay() {} -void NullDisplayPlugin::display(uint32_t sceneTexture, const glm::uvec2& sceneSize) {} -void NullDisplayPlugin::finishFrame() {} +void NullDisplayPlugin::submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) { + _container->releaseSceneTexture(sceneTexture); +} + +void NullDisplayPlugin::submitOverlayTexture(uint32_t overlayTexture, const glm::uvec2& overlaySize) { + _container->releaseOverlayTexture(overlayTexture); +} + void NullDisplayPlugin::stop() {} diff --git a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h index 8cd5c2bc37..c4052f38dd 100644 --- a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h @@ -19,10 +19,8 @@ public: virtual glm::uvec2 getRecommendedRenderSize() const override; virtual bool hasFocus() const override; - virtual void preRender() override; - virtual void preDisplay() override; - virtual void display(uint32_t sceneTexture, const glm::uvec2& sceneSize) override; - virtual void finishFrame() override; + virtual void submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) override; + virtual void submitOverlayTexture(uint32_t overlayTexture, const glm::uvec2& overlaySize) override; private: static const QString NAME; diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 09f4ba9897..e18cc6c82f 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -6,71 +6,167 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "OpenGLDisplayPlugin.h" -#include +#include +#include +#include + +#include +#include + +#include +#include +#include #include +#include #include +class PresentThread : public QThread, public Dependency { + using Mutex = std::mutex; + using Lock = std::unique_lock; + friend class OpenGLDisplayPlugin; +public: + + ~PresentThread() { + _shutdown = true; + wait(); + } + + void setNewDisplayPlugin(OpenGLDisplayPlugin* plugin) { + Lock lock(_mutex); + _newPlugin = plugin; + } + + virtual void run() override { + Q_ASSERT(_context); + while (!_shutdown) { + // Check before lock + if (_newPlugin != nullptr) { + Lock lock(_mutex); + // Check if we have a new plugin to activate + if (_newPlugin != nullptr) { + // Deactivate the old plugin + if (_activePlugin != nullptr) { + _activePlugin->uncustomizeContext(); + } + + _newPlugin->customizeContext(); + _activePlugin = _newPlugin; + _newPlugin = nullptr; + _context->doneCurrent(); + } + lock.unlock(); + } + + // If there's no active plugin, just sleep + if (_activePlugin == nullptr) { + QThread::usleep(100); + continue; + } + + // take the latest texture and present it + _activePlugin->present(); + + } + _context->doneCurrent(); + _context->moveToThread(qApp->thread()); + } + + +private: + bool _shutdown { false }; + Mutex _mutex; + QThread* _mainThread { nullptr }; + OpenGLDisplayPlugin* _newPlugin { nullptr }; + OpenGLDisplayPlugin* _activePlugin { nullptr }; + QOpenGLContext* _context { nullptr }; +}; OpenGLDisplayPlugin::OpenGLDisplayPlugin() { + _sceneTextureEscrow.setRecycler([this](GLuint texture){ + cleanupForSceneTexture(texture); + _container->releaseSceneTexture(texture); + }); + + _overlayTextureEscrow.setRecycler([this](GLuint texture) { + _container->releaseOverlayTexture(texture); + }); + connect(&_timer, &QTimer::timeout, this, [&] { - if (_active) { + if (_active && _sceneTextureEscrow.depth() < 1) { emit requestRender(); } }); } -OpenGLDisplayPlugin::~OpenGLDisplayPlugin() { +void OpenGLDisplayPlugin::cleanupForSceneTexture(uint32_t sceneTexture) { + Lock lock(_mutex); + Q_ASSERT(_sceneTextureToFrameIndexMap.contains(sceneTexture)); + _sceneTextureToFrameIndexMap.remove(sceneTexture); } -void OpenGLDisplayPlugin::preDisplay() { - makeCurrent(); -}; - -void OpenGLDisplayPlugin::preRender() { - // NOOP -} - -void OpenGLDisplayPlugin::finishFrame() { - swapBuffers(); - doneCurrent(); -}; - -void OpenGLDisplayPlugin::customizeContext() { - using namespace oglplus; - // TODO: write the poper code for linux -#if defined(Q_OS_WIN) - _vsyncSupported = wglewGetExtension("WGL_EXT_swap_control"); -#endif - - Context::BlendFunc(BlendFunction::SrcAlpha, BlendFunction::OneMinusSrcAlpha); - Context::Disable(Capability::Blend); - Context::Disable(Capability::DepthTest); - Context::Disable(Capability::CullFace); - - - _program = loadDefaultShader(); - _plane = loadPlane(_program); - - enableVsync(); -} void OpenGLDisplayPlugin::activate() { + _timer.start(2); + + // Start the present thread if necessary + auto presentThread = DependencyManager::get(); + if (!presentThread) { + DependencyManager::set(); + presentThread = DependencyManager::get(); + auto widget = _container->getPrimaryWidget(); + auto glContext = widget->context(); + auto context = glContext->contextHandle(); + glContext->moveToThread(presentThread.data()); + context->moveToThread(presentThread.data()); + + // Move the OpenGL context to the present thread + presentThread->_context = context; + + // Start execution + presentThread->start(); + } + presentThread->setNewDisplayPlugin(this); DisplayPlugin::activate(); - _timer.start(1); + emit requestRender(); } void OpenGLDisplayPlugin::stop() { - DisplayPlugin::activate(); _timer.stop(); } void OpenGLDisplayPlugin::deactivate() { - _active = false; _timer.stop(); + DisplayPlugin::deactivate(); +} +void OpenGLDisplayPlugin::customizeContext() { + auto presentThread = DependencyManager::get(); + Q_ASSERT(thread() == presentThread->thread()); + + bool makeCurrentResult = makeCurrent(); + Q_ASSERT(makeCurrentResult); + + // TODO: write the proper code for linux +#if defined(Q_OS_WIN) + _vsyncSupported = wglewGetExtension("WGL_EXT_swap_control"); +#endif + enableVsync(); + + using namespace oglplus; + Context::BlendFunc(BlendFunction::SrcAlpha, BlendFunction::OneMinusSrcAlpha); + Context::Disable(Capability::Blend); + Context::Disable(Capability::DepthTest); + Context::Disable(Capability::CullFace); + + _program = loadDefaultShader(); + _plane = loadPlane(_program); + + doneCurrent(); +} + +void OpenGLDisplayPlugin::uncustomizeContext() { makeCurrent(); - Q_ASSERT(0 == glGetError()); _program.reset(); _plane.reset(); doneCurrent(); @@ -118,13 +214,74 @@ bool OpenGLDisplayPlugin::eventFilter(QObject* receiver, QEvent* event) { return false; } -void OpenGLDisplayPlugin::display( - GLuint finalTexture, const glm::uvec2& sceneSize) { +void OpenGLDisplayPlugin::submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) { + { + Lock lock(_mutex); + _sceneTextureToFrameIndexMap[sceneTexture] = frameIndex; + } + + // Submit it to the presentation thread via escrow + _sceneTextureEscrow.submit(sceneTexture); +} + +void OpenGLDisplayPlugin::submitOverlayTexture(GLuint sceneTexture, const glm::uvec2& sceneSize) { + // Submit it to the presentation thread via escrow + _overlayTextureEscrow.submit(sceneTexture); +} + +void OpenGLDisplayPlugin::updateTextures() { + _currentSceneTexture = _sceneTextureEscrow.fetchAndRelease(_currentSceneTexture); + _currentOverlayTexture = _overlayTextureEscrow.fetchAndRelease(_currentOverlayTexture); +} + +void OpenGLDisplayPlugin::updateFramerate() { + uint64_t now = usecTimestampNow(); + static uint64_t lastSwapEnd { now }; + uint64_t diff = now - lastSwapEnd; + lastSwapEnd = now; + if (diff != 0) { + Lock lock(_mutex); + _usecsPerFrame.updateAverage(diff); + } +} + + +void OpenGLDisplayPlugin::internalPresent() { using namespace oglplus; - uvec2 size = getSurfaceSize(); + uvec2 size = getSurfacePixels(); Context::Viewport(size.x, size.y); - glBindTexture(GL_TEXTURE_2D, finalTexture); + Context::Clear().DepthBuffer(); + glBindTexture(GL_TEXTURE_2D, _currentSceneTexture); drawUnitQuad(); + swapBuffers(); + updateFramerate(); +} + +void OpenGLDisplayPlugin::present() { + auto makeCurrentResult = makeCurrent(); + Q_ASSERT(makeCurrentResult); + if (!makeCurrentResult) { + qDebug() << "Failed to make current"; + return; + } + + updateTextures(); + if (_currentSceneTexture) { + internalPresent(); + updateFramerate(); + } + doneCurrent(); +} + +float OpenGLDisplayPlugin::presentRate() { + float result { -1.0f }; + { + Lock lock(_mutex); + result = _usecsPerFrame.getAverage(); + result = 1.0f / result; + result *= USECS_PER_SECOND; + } + return result; } void OpenGLDisplayPlugin::drawUnitQuad() { @@ -151,3 +308,20 @@ bool OpenGLDisplayPlugin::isVsyncEnabled() { return true; #endif } +bool OpenGLDisplayPlugin::makeCurrent() { + static auto widget = _container->getPrimaryWidget(); + widget->makeCurrent(); + auto result = widget->context()->contextHandle() == QOpenGLContext::currentContext(); + Q_ASSERT(result); + return result; +} + +void OpenGLDisplayPlugin::doneCurrent() { + static auto widget = _container->getPrimaryWidget(); + widget->doneCurrent(); +} + +void OpenGLDisplayPlugin::swapBuffers() { + static auto widget = _container->getPrimaryWidget(); + widget->swapBuffers(); +} diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index 43d8e5af6b..4426bfd5ef 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -9,42 +9,74 @@ #include "DisplayPlugin.h" -#include -#include +#include -class GlWindow; -class QOpenGLContext; +#include +#include +#include +#include class OpenGLDisplayPlugin : public DisplayPlugin { +protected: + using Mutex = std::recursive_mutex; + using Lock = std::unique_lock; public: OpenGLDisplayPlugin(); - virtual ~OpenGLDisplayPlugin(); - virtual void preRender() override; - virtual void preDisplay() override; - virtual void finishFrame() override; - virtual void activate() override; virtual void deactivate() override; virtual void stop() override; virtual bool eventFilter(QObject* receiver, QEvent* event) override; - virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize) override; + virtual void submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) override; + virtual void submitOverlayTexture(uint32_t overlayTexture, const glm::uvec2& overlaySize) override; + virtual float presentRate() override; + + virtual glm::uvec2 getRecommendedRenderSize() const { + return getSurfacePixels(); + } + + virtual glm::uvec2 getRecommendedUiSize() const { + return getSurfaceSize(); + } protected: - virtual void customizeContext(); - virtual void drawUnitQuad(); - virtual glm::uvec2 getSurfaceSize() const = 0; - virtual void makeCurrent() = 0; - virtual void doneCurrent() = 0; - virtual void swapBuffers() = 0; + friend class PresentThread; + virtual glm::uvec2 getSurfaceSize() const = 0; + virtual glm::uvec2 getSurfacePixels() const = 0; + + // FIXME make thread safe? virtual bool isVsyncEnabled(); virtual void enableVsync(bool enable = true); + // These functions must only be called on the presentation thread + virtual void customizeContext(); + virtual void uncustomizeContext(); + virtual void cleanupForSceneTexture(uint32_t sceneTexture); + void present(); + void updateTextures(); + void updateFramerate(); + void drawUnitQuad(); + bool makeCurrent(); + void doneCurrent(); + void swapBuffers(); + // Plugin specific functionality to composite the scene and overlay and present the result + virtual void internalPresent(); + mutable QTimer _timer; ProgramPtr _program; ShapeWrapperPtr _plane; - bool _vsyncSupported{ false }; + bool _vsyncSupported { false }; + + Mutex _mutex; + SimpleMovingAverage _usecsPerFrame { 10 }; + QMap _sceneTextureToFrameIndexMap; + + GLuint _currentSceneTexture { 0 }; + GLuint _currentOverlayTexture { 0 }; + + GLTextureEscrow _overlayTextureEscrow; + GLTextureEscrow _sceneTextureEscrow; }; diff --git a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp index e6fb2be2f5..b215b19b15 100644 --- a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp @@ -11,14 +11,7 @@ #include "plugins/PluginContainer.h" -WindowOpenGLDisplayPlugin::WindowOpenGLDisplayPlugin() { -} - -glm::uvec2 WindowOpenGLDisplayPlugin::getRecommendedRenderSize() const { - return getSurfaceSize(); -} - -glm::uvec2 WindowOpenGLDisplayPlugin::getSurfaceSize() const { +glm::uvec2 WindowOpenGLDisplayPlugin::getSurfacePixels() const { uvec2 result; if (_window) { result = toGlm(_window->geometry().size() * _window->devicePixelRatio()); @@ -26,8 +19,7 @@ glm::uvec2 WindowOpenGLDisplayPlugin::getSurfaceSize() const { return result; } - -glm::uvec2 WindowOpenGLDisplayPlugin::getRecommendedUiSize() const { +glm::uvec2 WindowOpenGLDisplayPlugin::getSurfaceSize() const { uvec2 result; if (_window) { result = toGlm(_window->geometry().size()); @@ -40,11 +32,8 @@ bool WindowOpenGLDisplayPlugin::hasFocus() const { } void WindowOpenGLDisplayPlugin::activate() { + _window = _container->getPrimaryWidget(); OpenGLDisplayPlugin::activate(); - _window = _container->getPrimarySurface(); - _window->makeCurrent(); - customizeContext(); - _window->doneCurrent(); } void WindowOpenGLDisplayPlugin::deactivate() { @@ -52,14 +41,3 @@ void WindowOpenGLDisplayPlugin::deactivate() { _window = nullptr; } -void WindowOpenGLDisplayPlugin::makeCurrent() { - _window->makeCurrent(); -} - -void WindowOpenGLDisplayPlugin::doneCurrent() { - _window->doneCurrent(); -} - -void WindowOpenGLDisplayPlugin::swapBuffers() { - _window->swapBuffers(); -} diff --git a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.h index fc7691fc56..51e5d32503 100644 --- a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.h @@ -9,21 +9,17 @@ #include "OpenGLDisplayPlugin.h" -class QGLWidget; +class QWidget; class WindowOpenGLDisplayPlugin : public OpenGLDisplayPlugin { public: - WindowOpenGLDisplayPlugin(); - virtual glm::uvec2 getRecommendedRenderSize() const override; - virtual glm::uvec2 getRecommendedUiSize() const override; virtual bool hasFocus() const override; virtual void activate() override; virtual void deactivate() override; protected: virtual glm::uvec2 getSurfaceSize() const override final; - virtual void makeCurrent() override; - virtual void doneCurrent() override; - virtual void swapBuffers() override; - QGLWidget* _window{ nullptr }; + virtual glm::uvec2 getSurfacePixels() const override final; + + QWidget* _window { nullptr }; }; diff --git a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp index 4278165e25..68a711a847 100644 --- a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp @@ -152,7 +152,7 @@ glm::mat4 OpenVrDisplayPlugin::getEyeToHeadTransform(Eye eye) const { return _eyesData[eye]._eyeOffset; } -glm::mat4 OpenVrDisplayPlugin::getHeadPose() const { +glm::mat4 OpenVrDisplayPlugin::getHeadPose(uint32_t frameIndex) const { return _trackedDevicePoseMat4[0]; } @@ -160,26 +160,26 @@ void OpenVrDisplayPlugin::customizeContext() { WindowOpenGLDisplayPlugin::customizeContext(); } -void OpenVrDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSize) { - // Flip y-axis since GL UV coords are backwards. - static vr::Compositor_TextureBounds leftBounds{ 0, 1, 0.5f, 0 }; - static vr::Compositor_TextureBounds rightBounds{ 0.5f, 1, 1, 0 }; - _compositor->Submit(vr::Eye_Left, (void*)finalTexture, &leftBounds); - _compositor->Submit(vr::Eye_Right, (void*)finalTexture, &rightBounds); - glFinish(); -} +//void OpenVrDisplayPlugin::display(uint32_t frameIndex, uint32_t finalTexture, const glm::uvec2& sceneSize) { +// // Flip y-axis since GL UV coords are backwards. +// static vr::Compositor_TextureBounds leftBounds{ 0, 1, 0.5f, 0 }; +// static vr::Compositor_TextureBounds rightBounds{ 0.5f, 1, 1, 0 }; +// _compositor->Submit(vr::Eye_Left, (void*)finalTexture, &leftBounds); +// _compositor->Submit(vr::Eye_Right, (void*)finalTexture, &rightBounds); +// glFinish(); +//} -void OpenVrDisplayPlugin::finishFrame() { -// swapBuffers(); - doneCurrent(); - _compositor->WaitGetPoses(_trackedDevicePose, vr::k_unMaxTrackedDeviceCount); - for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { - _trackedDevicePoseMat4[i] = _sensorResetMat * toGlm(_trackedDevicePose[i].mDeviceToAbsoluteTracking); - } - openvr_for_each_eye([&](vr::Hmd_Eye eye) { - _eyesData[eye]._pose = _trackedDevicePoseMat4[0]; - }); -}; +//void OpenVrDisplayPlugin::finishFrame() { +//// swapBuffers(); +// doneCurrent(); +// _compositor->WaitGetPoses(_trackedDevicePose, vr::k_unMaxTrackedDeviceCount); +// for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { +// _trackedDevicePoseMat4[i] = _sensorResetMat * toGlm(_trackedDevicePose[i].mDeviceToAbsoluteTracking); +// } +// openvr_for_each_eye([&](vr::Hmd_Eye eye) { +// _eyesData[eye]._pose = _trackedDevicePoseMat4[0]; +// }); +//}; #endif diff --git a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.h index 15d37d9de8..c8887276b7 100644 --- a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.h @@ -31,13 +31,11 @@ public: virtual void resetSensors() override; virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override; - virtual glm::mat4 getHeadPose() const override; + virtual glm::mat4 getHeadPose(uint32_t frameIndex) const override; protected: - virtual void display(GLuint finalTexture, const glm::uvec2& sceneSize) override; +// virtual void display(uint32_t frameIndex, uint32_t finalTexture, const glm::uvec2& sceneSize) override; virtual void customizeContext() override; - // Do not perform swap in finish - virtual void finishFrame() override; private: vr::IVRSystem* _hmd { nullptr }; diff --git a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp index 72921b4f90..4332c53d81 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp @@ -66,10 +66,6 @@ glm::uvec2 InterleavedStereoDisplayPlugin::getRecommendedRenderSize() const { return result; } -void InterleavedStereoDisplayPlugin::display( - GLuint finalTexture, const glm::uvec2& sceneSize) { - using namespace oglplus; - _program->Bind(); - Uniform(*_program, "textureSize").SetValue(sceneSize); - WindowOpenGLDisplayPlugin::display(finalTexture, sceneSize); +void InterleavedStereoDisplayPlugin::internalPresent() { + // FIXME } diff --git a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h index 3044d91247..b9b3566349 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h @@ -19,7 +19,8 @@ public: virtual void customizeContext() override; virtual glm::uvec2 getRecommendedRenderSize() const override; - void display(GLuint finalTexture, const glm::uvec2& sceneSize) override; + + void internalPresent() override; private: static const QString NAME; diff --git a/libraries/gl/src/gl/GLEscrow.h b/libraries/gl/src/gl/GLEscrow.h index db9f033de8..d860f1239c 100644 --- a/libraries/gl/src/gl/GLEscrow.h +++ b/libraries/gl/src/gl/GLEscrow.h @@ -76,7 +76,7 @@ public: } }; - using Mutex = std::mutex; + using Mutex = std::recursive_mutex; using Lock = std::unique_lock; using Recycler = std::function; // deque gives us random access, double ended push & pop and size, all in constant time @@ -130,6 +130,21 @@ public: return result; } + // Returns the next available resource provided by the submitter, + // or if none is available (which could mean either the submission + // list is empty or that the first item on the list isn't yet signaled + // Also releases any previous texture held by the caller + T fetchAndRelease(T oldValue) { + T result = fetch(); + if (!result) { + return oldValue; + } + if (oldValue) { + release(oldValue); + } + return result; + } + // If fetch returns a non-zero value, it's the responsibility of the // client to release it at some point void release(T t, GLsync readSync = 0) { @@ -162,7 +177,12 @@ private: pop(_releases); } - trash.swap(_trash); + { + // FIXME I don't think this lock should be necessary, only the submitting thread + // touches the trash + Lock lock(_mutex); + trash.swap(_trash); + } } // FIXME maybe doing a timing on the deleters and warn if it's taking excessive time? diff --git a/libraries/plugins/src/plugins/DisplayPlugin.h b/libraries/plugins/src/plugins/DisplayPlugin.h index 5b00391f09..928b72970b 100644 --- a/libraries/plugins/src/plugins/DisplayPlugin.h +++ b/libraries/plugins/src/plugins/DisplayPlugin.h @@ -65,29 +65,15 @@ public: // processing messages in the middle of submitFrame virtual void stop() = 0; - /** - * Called by the application before the frame rendering. Can be used for - * render timing related calls (for instance, the Oculus begin frame timing - * call) - */ - virtual void preRender() = 0; - /** - * Called by the application immediately before calling the display function. - * For OpenGL based plugins, this is the best place to put activate the output - * OpenGL context - */ - virtual void preDisplay() = 0; - /** * Sends the scene texture to the display plugin. */ - virtual void display(uint32_t sceneTexture, const glm::uvec2& sceneSize) = 0; + virtual void submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) = 0; /** - * Called by the application immeidately after display. For OpenGL based - * displays, this is the best place to put the buffer swap - */ - virtual void finishFrame() = 0; + * Sends the scene texture to the display plugin. + */ + virtual void submitOverlayTexture(uint32_t overlayTexture, const glm::uvec2& overlaySize) = 0; // Does the rendering surface have current focus? virtual bool hasFocus() const = 0; @@ -116,12 +102,12 @@ public: static const glm::mat4 transform; return transform; } - virtual glm::mat4 getHeadPose() const { + virtual glm::mat4 getHeadPose(uint32_t frameIndex) const { static const glm::mat4 pose; return pose; } // Needed for timewarp style features - virtual void setEyeRenderPose(Eye eye, const glm::mat4& pose) { + virtual void setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm::mat4& pose) { // NOOP } @@ -129,8 +115,8 @@ public: virtual void abandonCalibration() {} virtual void resetSensors() {} - virtual float devicePixelRatio() { return 1.0; } - + virtual float devicePixelRatio() { return 1.0f; } + virtual float presentRate() { return -1.0f; } static const QString& MENU_PATH(); signals: diff --git a/libraries/plugins/src/plugins/PluginContainer.h b/libraries/plugins/src/plugins/PluginContainer.h index f013bfe3bf..25c2bcb11f 100644 --- a/libraries/plugins/src/plugins/PluginContainer.h +++ b/libraries/plugins/src/plugins/PluginContainer.h @@ -8,11 +8,15 @@ #pragma once #include +#include #include class QAction; class QGLWidget; class QScreen; +class QOpenGLContext; +class QWindow; + class DisplayPlugin; class PluginContainer { @@ -30,7 +34,12 @@ public: virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) = 0; virtual void showDisplayPluginsTools() = 0; virtual void requestReset() = 0; - virtual QGLWidget* getPrimarySurface() = 0; + virtual bool makeRenderingContextCurrent() = 0; + virtual void releaseSceneTexture(uint32_t texture) = 0; + virtual void releaseOverlayTexture(uint32_t texture) = 0; + virtual QGLWidget* getPrimaryWidget() = 0; + virtual QWindow* getPrimaryWindow() = 0; + virtual QOpenGLContext* getPrimaryContext() = 0; virtual bool isForeground() = 0; virtual const DisplayPlugin* getActiveDisplayPlugin() const = 0; }; diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp index 7fd956a08f..805ad75e95 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp @@ -15,13 +15,6 @@ uvec2 OculusBaseDisplayPlugin::getRecommendedRenderSize() const { return _desiredFramebufferSize; } -void OculusBaseDisplayPlugin::preRender() { -#if (OVR_MAJOR_VERSION >= 6) - ovrFrameTiming ftiming = ovr_GetFrameTiming(_hmd, _frameIndex); - _trackingState = ovr_GetTrackingState(_hmd, ftiming.DisplayMidpointSeconds); -#endif -} - glm::mat4 OculusBaseDisplayPlugin::getProjection(Eye eye, const glm::mat4& baseProjection) const { return _eyeProjections[eye]; } @@ -29,7 +22,6 @@ glm::mat4 OculusBaseDisplayPlugin::getProjection(Eye eye, const glm::mat4& baseP void OculusBaseDisplayPlugin::resetSensors() { #if (OVR_MAJOR_VERSION >= 6) ovr_RecenterPose(_hmd); - preRender(); #endif } @@ -37,15 +29,14 @@ glm::mat4 OculusBaseDisplayPlugin::getEyeToHeadTransform(Eye eye) const { return glm::translate(mat4(), toGlm(_eyeOffsets[eye])); } -glm::mat4 OculusBaseDisplayPlugin::getHeadPose() const { - return toGlm(_trackingState.HeadPose.ThePose); +glm::mat4 OculusBaseDisplayPlugin::getHeadPose(uint32_t frameIndex) const { +#if (OVR_MAJOR_VERSION >= 6) + auto frameTiming = ovr_GetFrameTiming(_hmd, frameIndex); + auto trackingState = ovr_GetTrackingState(_hmd, frameTiming.DisplayMidpointSeconds); + return toGlm(trackingState.HeadPose.ThePose); +#endif } -void OculusBaseDisplayPlugin::setEyeRenderPose(Eye eye, const glm::mat4& pose) { - _eyePoses[eye] = ovrPoseFromGlm(pose); -} - - bool OculusBaseDisplayPlugin::isSupported() const { #if (OVR_MAJOR_VERSION >= 6) if (!OVR_SUCCESS(ovr_Initialize(nullptr))) { @@ -64,9 +55,11 @@ bool OculusBaseDisplayPlugin::isSupported() const { // DLL based display plugins MUST initialize GLEW inside the DLL code. void OculusBaseDisplayPlugin::customizeContext() { + makeCurrent(); glewExperimental = true; GLenum err = glewInit(); glGetError(); + doneCurrent(); WindowOpenGLDisplayPlugin::customizeContext(); } @@ -123,8 +116,6 @@ void OculusBaseDisplayPlugin::activate() { eyeSizes[0].x + eyeSizes[1].x, std::max(eyeSizes[0].y, eyeSizes[1].y)); - _frameIndex = 0; - if (!OVR_SUCCESS(ovr_ConfigureTracking(_hmd, ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection, 0))) { qFatal("Could not attach to sensor device"); @@ -159,9 +150,6 @@ void OculusBaseDisplayPlugin::deactivate() { #endif } -void OculusBaseDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSize) { - ++_frameIndex; -} float OculusBaseDisplayPlugin::getIPD() const { float result = OVR_DEFAULT_IPD; diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.h b/plugins/oculus/src/OculusBaseDisplayPlugin.h index ba1924bfff..711be6aa5e 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.h +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.h @@ -30,24 +30,18 @@ public: virtual glm::uvec2 getRecommendedUiSize() const override final { return uvec2(1920, 1080); } virtual void resetSensors() override final; virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override final; - virtual glm::mat4 getHeadPose() const override final; - virtual void setEyeRenderPose(Eye eye, const glm::mat4& pose) override final; virtual float getIPD() const override final; + virtual glm::mat4 getHeadPose(uint32_t frameIndex) const override; protected: virtual void customizeContext() override; - virtual void preRender() override final; - virtual void display(GLuint finalTexture, const glm::uvec2& sceneSize) override; protected: - ovrPosef _eyePoses[2]; ovrVector3f _eyeOffsets[2]; mat4 _eyeProjections[3]; mat4 _compositeEyeProjections[2]; uvec2 _desiredFramebufferSize; - ovrTrackingState _trackingState; - unsigned int _frameIndex{ 0 }; #if (OVR_MAJOR_VERSION >= 6) ovrHmd _hmd; diff --git a/plugins/oculus/src/OculusDebugDisplayPlugin.cpp b/plugins/oculus/src/OculusDebugDisplayPlugin.cpp index 7a8b355ddd..26bb3cf9b2 100644 --- a/plugins/oculus/src/OculusDebugDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusDebugDisplayPlugin.cpp @@ -28,13 +28,3 @@ void OculusDebugDisplayPlugin::customizeContext() { OculusBaseDisplayPlugin::customizeContext(); enableVsync(false); } - -void OculusDebugDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSize) { - WindowOpenGLDisplayPlugin::display(finalTexture, sceneSize); - OculusBaseDisplayPlugin::display(finalTexture, sceneSize); -} - -void OculusDebugDisplayPlugin::finishFrame() { - swapBuffers(); - doneCurrent(); -}; diff --git a/plugins/oculus/src/OculusDebugDisplayPlugin.h b/plugins/oculus/src/OculusDebugDisplayPlugin.h index d23c6ba567..04b68704cc 100644 --- a/plugins/oculus/src/OculusDebugDisplayPlugin.h +++ b/plugins/oculus/src/OculusDebugDisplayPlugin.h @@ -15,10 +15,7 @@ public: virtual bool isSupported() const override; protected: - virtual void display(GLuint finalTexture, const glm::uvec2& sceneSize) override; virtual void customizeContext() override; - // Do not perform swap in finish - virtual void finishFrame() override; private: static const QString NAME; diff --git a/plugins/oculus/src/OculusDisplayPlugin.cpp b/plugins/oculus/src/OculusDisplayPlugin.cpp index 923b8bde6e..bcb39f5100 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusDisplayPlugin.cpp @@ -144,7 +144,6 @@ static const QString MONO_PREVIEW = "Mono Preview"; static const QString FRAMERATE = DisplayPlugin::MENU_PATH() + ">Framerate"; void OculusDisplayPlugin::activate() { - _container->addMenuItem(MENU_PATH(), MONO_PREVIEW, [this](bool clicked) { _monoPreview = clicked; @@ -155,6 +154,8 @@ void OculusDisplayPlugin::activate() { void OculusDisplayPlugin::customizeContext() { OculusBaseDisplayPlugin::customizeContext(); + bool makeCurrentResult = makeCurrent(); + Q_ASSERT(makeCurrentResult); #if (OVR_MAJOR_VERSION >= 6) _sceneFbo = SwapFboPtr(new SwapFramebufferWrapper(_hmd)); _sceneFbo->Init(getRecommendedRenderSize()); @@ -168,20 +169,24 @@ void OculusDisplayPlugin::customizeContext() { enableVsync(false); // Only enable mirroring if we know vsync is disabled _enablePreview = !isVsyncEnabled(); + doneCurrent(); } -void OculusDisplayPlugin::deactivate() { +void OculusDisplayPlugin::uncustomizeContext() { #if (OVR_MAJOR_VERSION >= 6) makeCurrent(); _sceneFbo.reset(); doneCurrent(); #endif - - OculusBaseDisplayPlugin::deactivate(); + OculusBaseDisplayPlugin::uncustomizeContext(); } -void OculusDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSize) { +void OculusDisplayPlugin::internalPresent() { #if (OVR_MAJOR_VERSION >= 6) + if (!_currentSceneTexture) { + return; + } + using namespace oglplus; // Need to make sure only the display plugin is responsible for // controlling vsync @@ -196,7 +201,7 @@ void OculusDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSi } else { Context::Viewport(windowSize.x, windowSize.y); } - glBindTexture(GL_TEXTURE_2D, finalTexture); + glBindTexture(GL_TEXTURE_2D, _currentSceneTexture); GLenum err = glGetError(); Q_ASSERT(0 == err); drawUnitQuad(); @@ -205,16 +210,24 @@ void OculusDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSi _sceneFbo->Bound([&] { auto size = _sceneFbo->size; Context::Viewport(size.x, size.y); - glBindTexture(GL_TEXTURE_2D, finalTexture); + glBindTexture(GL_TEXTURE_2D, _currentSceneTexture); GLenum err = glGetError(); drawUnitQuad(); }); - ovr_for_each_eye([&](ovrEyeType eye) { - _sceneLayer.RenderPose[eye] = _eyePoses[eye]; - }); + uint32_t frameIndex { 0 }; + EyePoses eyePoses; + { + Lock lock(_mutex); + Q_ASSERT(_sceneTextureToFrameIndexMap.contains(_currentSceneTexture)); + frameIndex = _sceneTextureToFrameIndexMap[_currentSceneTexture]; + Q_ASSERT(_frameEyePoses.contains(frameIndex)); + eyePoses = _frameEyePoses[frameIndex]; + } + + _sceneLayer.RenderPose[ovrEyeType::ovrEye_Left] = eyePoses.first; + _sceneLayer.RenderPose[ovrEyeType::ovrEye_Right] = eyePoses.second; - auto windowSize = toGlm(_window->size()); { ovrViewScaleDesc viewScaleDesc; viewScaleDesc.HmdSpaceToWorldScaleInMeters = 1.0f; @@ -228,19 +241,26 @@ void OculusDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSi } } _sceneFbo->Increment(); - - ++_frameIndex; #endif -} -/* + /* The swapbuffer call here is only required if we want to mirror the content to the screen. - However, it should only be done if we can reliably disable v-sync on the mirror surface, + However, it should only be done if we can reliably disable v-sync on the mirror surface, otherwise the swapbuffer delay will interefere with the framerate of the headset -*/ -void OculusDisplayPlugin::finishFrame() { + */ if (_enablePreview) { swapBuffers(); } - doneCurrent(); -}; +} + +void OculusDisplayPlugin::setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm::mat4& pose) { + auto ovrPose = ovrPoseFromGlm(pose); + { + Lock lock(_mutex); + if (eye == Eye::Left) { + _frameEyePoses[frameIndex].first = ovrPose; + } else { + _frameEyePoses[frameIndex].second = ovrPose; + } + } +} diff --git a/plugins/oculus/src/OculusDisplayPlugin.h b/plugins/oculus/src/OculusDisplayPlugin.h index c1224ecf3a..5509715b9f 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.h +++ b/plugins/oculus/src/OculusDisplayPlugin.h @@ -15,22 +15,21 @@ using SwapFboPtr = QSharedPointer; class OculusDisplayPlugin : public OculusBaseDisplayPlugin { public: virtual void activate() override; - virtual void deactivate() override; virtual const QString & getName() const override; + virtual void setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm::mat4& pose) override final; protected: - virtual void display(GLuint finalTexture, const glm::uvec2& sceneSize) override; + virtual void internalPresent() override; virtual void customizeContext() override; - // Do not perform swap in finish - virtual void finishFrame() override; + virtual void uncustomizeContext() override; private: + using EyePoses = std::pair; static const QString NAME; bool _enablePreview { false }; bool _monoPreview { true }; + QMap _frameEyePoses; -#if (OVR_MAJOR_VERSION >= 6) SwapFboPtr _sceneFbo; -#endif }; diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index f93580e5a3..37c560e9ad 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -11,7 +11,6 @@ namespace Oculus { ovrHmd _hmd; - unsigned int _frameIndex{ 0 }; ovrEyeRenderDesc _eyeRenderDescs[2]; ovrPosef _eyePoses[2]; ovrVector3f _eyeOffsets[2]; diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h index 6e3f864aee..ccf1ffdb57 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h @@ -46,7 +46,6 @@ private: static const QString NAME; ovrHmd _hmd; - unsigned int _frameIndex; ovrTrackingState _trackingState; ovrEyeRenderDesc _eyeRenderDescs[2]; ovrPosef _eyePoses[2]; diff --git a/tests/controllers/src/main.cpp b/tests/controllers/src/main.cpp index 664a894e44..c5c038fde3 100644 --- a/tests/controllers/src/main.cpp +++ b/tests/controllers/src/main.cpp @@ -91,7 +91,12 @@ public: virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) override {} virtual void showDisplayPluginsTools() override {} virtual void requestReset() override {} - virtual QGLWidget* getPrimarySurface() override { return nullptr; } + virtual bool makeRenderingContextCurrent() override { return true; } + virtual void releaseSceneTexture(uint32_t texture) override {} + virtual void releaseOverlayTexture(uint32_t texture) override {} + virtual QGLWidget* getPrimaryWidget() override { return nullptr; } + virtual QWindow* getPrimaryWindow() override { return nullptr; } + virtual QOpenGLContext* getPrimaryContext() override { return nullptr; } virtual bool isForeground() override { return true; } virtual const DisplayPlugin* getActiveDisplayPlugin() const override { return nullptr; } };