mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-04-07 10:02:24 +02:00
Prototyping threaded present
This commit is contained in:
parent
d9a1563396
commit
b9ace94ff1
37 changed files with 600 additions and 387 deletions
|
@ -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;
|
||||
|
|
|
@ -150,6 +150,8 @@
|
|||
#include "InterfaceParentFinder.h"
|
||||
|
||||
|
||||
#include <gpu/GLBackend.h>
|
||||
#include <QtGui/QOpenGLContext>
|
||||
|
||||
// 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<HMDScriptingInterface>();
|
||||
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<QPair<QString, QString>> _currentDisplayPluginActions;
|
||||
QVector<QPair<QString, QString>> _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();
|
||||
}
|
||||
|
|
|
@ -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<QPair<QString, QString>> _currentDisplayPluginActions;
|
||||
QVector<QPair<QString, QString>> _currentInputPluginActions;
|
||||
QMap<uint32_t, gpu::FramebufferPointer> _lockedFramebufferMap;
|
||||
|
||||
MainWindow* _window;
|
||||
|
||||
ToolWindow* _toolWindow;
|
||||
|
|
|
@ -13,27 +13,6 @@
|
|||
#include "Application.h"
|
||||
#include "GLCanvas.h"
|
||||
|
||||
#include <QWindow>
|
||||
|
||||
#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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,17 +1,23 @@
|
|||
#include "PluginContainerProxy.h"
|
||||
|
||||
#include <QScreen>
|
||||
#include <QWindow>
|
||||
#include <QtGui/QScreen>
|
||||
#include <QtGui/QWindow>
|
||||
|
||||
#include <plugins/Plugin.h>
|
||||
#include <plugins/PluginManager.h>
|
||||
#include <display-plugins/DisplayPlugin.h>
|
||||
#include <gl/GlWindow.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <FramebufferCache.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "MainWindow.h"
|
||||
#include "GLCanvas.h"
|
||||
#include "ui/DialogsManager.h"
|
||||
|
||||
#include <gl/OffscreenGLCanvas.h>
|
||||
#include <QtGui/QOpenGLContext>
|
||||
|
||||
PluginContainerProxy::PluginContainerProxy() {
|
||||
}
|
||||
|
||||
|
@ -36,30 +42,31 @@ extern QVector<QPair<QString, QString>> _currentInputPluginActions;
|
|||
std::map<QString, QActionGroup*> _exclusiveGroups;
|
||||
|
||||
QAction* PluginContainerProxy::addMenuItem(const QString& path, const QString& name, std::function<void(bool)> 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<DialogsManager>()->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>();
|
||||
framebufferCache->releaseFramebuffer(framebufferPointer);
|
||||
}
|
||||
|
||||
void PluginContainerProxy::releaseOverlayTexture(uint32_t texture) {
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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<AvatarManager>()->getMyAvatar()->doUpdateBillboard();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <LODManager.h>
|
||||
#include <OffscreenUi.h>
|
||||
#include <PerfStat.h>
|
||||
#include <plugins/DisplayPlugin.h>
|
||||
|
||||
#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());
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -30,44 +30,41 @@ const QString& Basic2DWindowOpenGLDisplayPlugin::getName() const {
|
|||
return NAME;
|
||||
}
|
||||
|
||||
std::vector<QAction*> _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;
|
||||
|
|
|
@ -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<QAction*> _framerateActions;
|
||||
QAction* _vsyncAction { nullptr };
|
||||
uint32_t _framerateTarget { 0 };
|
||||
int _fullscreenTarget{ -1 };
|
||||
bool _wantVsync { true };
|
||||
};
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
//
|
||||
#include "NullDisplayPlugin.h"
|
||||
|
||||
#include <plugins/PluginContainer.h>
|
||||
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() {}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -6,71 +6,167 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "OpenGLDisplayPlugin.h"
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QTimer>
|
||||
|
||||
#include <QtOpenGL/QGLWidget>
|
||||
#include <QtGui/QOpenGLContext>
|
||||
|
||||
#include <NumericalConstants.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <plugins/PluginContainer.h>
|
||||
#include <gl/Config.h>
|
||||
#include <gl/GLEscrow.h>
|
||||
#include <GLMHelpers.h>
|
||||
|
||||
class PresentThread : public QThread, public Dependency {
|
||||
using Mutex = std::mutex;
|
||||
using Lock = std::unique_lock<Mutex>;
|
||||
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<PresentThread>();
|
||||
if (!presentThread) {
|
||||
DependencyManager::set<PresentThread>();
|
||||
presentThread = DependencyManager::get<PresentThread>();
|
||||
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<PresentThread>();
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -9,42 +9,74 @@
|
|||
|
||||
#include "DisplayPlugin.h"
|
||||
|
||||
#include <QTimer>
|
||||
#include <gl/OglplusHelpers.h>
|
||||
#include <QtCore/QTimer>
|
||||
|
||||
class GlWindow;
|
||||
class QOpenGLContext;
|
||||
#include <GLMHelpers.h>
|
||||
#include <SimpleMovingAverage.h>
|
||||
#include <gl/OglplusHelpers.h>
|
||||
#include <gl/GLEscrow.h>
|
||||
|
||||
class OpenGLDisplayPlugin : public DisplayPlugin {
|
||||
protected:
|
||||
using Mutex = std::recursive_mutex;
|
||||
using Lock = std::unique_lock<Mutex>;
|
||||
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<uint32_t, uint32_t> _sceneTextureToFrameIndexMap;
|
||||
|
||||
GLuint _currentSceneTexture { 0 };
|
||||
GLuint _currentOverlayTexture { 0 };
|
||||
|
||||
GLTextureEscrow _overlayTextureEscrow;
|
||||
GLTextureEscrow _sceneTextureEscrow;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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<ivec2>(*_program, "textureSize").SetValue(sceneSize);
|
||||
WindowOpenGLDisplayPlugin::display(finalTexture, sceneSize);
|
||||
void InterleavedStereoDisplayPlugin::internalPresent() {
|
||||
// FIXME
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -76,7 +76,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
using Mutex = std::mutex;
|
||||
using Mutex = std::recursive_mutex;
|
||||
using Lock = std::unique_lock<Mutex>;
|
||||
using Recycler = std::function<void(T t)>;
|
||||
// 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?
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -8,11 +8,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <stdint.h>
|
||||
#include <QString>
|
||||
|
||||
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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,22 +15,21 @@ using SwapFboPtr = QSharedPointer<SwapFramebufferWrapper>;
|
|||
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<ovrPosef, ovrPosef>;
|
||||
static const QString NAME;
|
||||
bool _enablePreview { false };
|
||||
bool _monoPreview { true };
|
||||
QMap<uint32_t, EyePoses> _frameEyePoses;
|
||||
|
||||
#if (OVR_MAJOR_VERSION >= 6)
|
||||
SwapFboPtr _sceneFbo;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
namespace Oculus {
|
||||
ovrHmd _hmd;
|
||||
unsigned int _frameIndex{ 0 };
|
||||
ovrEyeRenderDesc _eyeRenderDescs[2];
|
||||
ovrPosef _eyePoses[2];
|
||||
ovrVector3f _eyeOffsets[2];
|
||||
|
|
|
@ -46,7 +46,6 @@ private:
|
|||
static const QString NAME;
|
||||
|
||||
ovrHmd _hmd;
|
||||
unsigned int _frameIndex;
|
||||
ovrTrackingState _trackingState;
|
||||
ovrEyeRenderDesc _eyeRenderDescs[2];
|
||||
ovrPosef _eyePoses[2];
|
||||
|
|
|
@ -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; }
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue