Merge pull request #7044 from jherico/optional_threaded_present

Make threaded present optional
This commit is contained in:
Brad Hefta-Gaub 2016-02-08 17:17:31 -08:00
commit 89648f3c2e
2 changed files with 73 additions and 22 deletions

View file

@ -21,11 +21,13 @@
#include <gl/GLWidget.h>
#include <NumericalConstants.h>
#include <DependencyManager.h>
#include <plugins/PluginContainer.h>
#include <gl/Config.h>
#include <gl/GLEscrow.h>
#include <GLMHelpers.h>
#if THREADED_PRESENT
class PresentThread : public QThread, public Dependency {
using Mutex = std::mutex;
using Condition = std::condition_variable;
@ -33,16 +35,25 @@ class PresentThread : public QThread, public Dependency {
public:
PresentThread() {
connect(qApp, &QCoreApplication::aboutToQuit, [this]{
_shutdown = true;
connect(qApp, &QCoreApplication::aboutToQuit, [this] {
shutdown();
});
}
~PresentThread() {
_shutdown = true;
wait();
shutdown();
}
void shutdown() {
if (isRunning()) {
Lock lock(_mutex);
_shutdown = true;
_condition.wait(lock, [&] { return !_shutdown; });
qDebug() << "Present thread shutdown";
}
}
void setNewDisplayPlugin(OpenGLDisplayPlugin* plugin) {
Lock lock(_mutex);
_newPlugin = plugin;
@ -120,6 +131,10 @@ public:
}
_context->doneCurrent();
_context->moveToThread(qApp->thread());
Lock lock(_mutex);
_shutdown = false;
_condition.notify_one();
}
void withMainThreadContext(std::function<void()> f) {
@ -159,16 +174,14 @@ private:
QGLContext* _context { nullptr };
};
#endif
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, [&] {
#ifdef Q_OS_MAC
// On Mac, QT thread timing is such that we can miss one or even two cycles quite often, giving a render rate (including update/simulate)
@ -191,9 +204,10 @@ void OpenGLDisplayPlugin::cleanupForSceneTexture(uint32_t sceneTexture) {
void OpenGLDisplayPlugin::activate() {
_timer.start(1);
_vsyncSupported = _container->getPrimaryWidget()->isVsyncSupported();
#if THREADED_PRESENT
_timer.start(1);
// Start the present thread if necessary
auto presentThread = DependencyManager::get<PresentThread>();
if (!presentThread) {
@ -208,7 +222,15 @@ void OpenGLDisplayPlugin::activate() {
presentThread->start();
}
presentThread->setNewDisplayPlugin(this);
#else
static auto widget = _container->getPrimaryWidget();
widget->makeCurrent();
customizeContext();
_container->makeRenderingContextCurrent();
#endif
DisplayPlugin::activate();
}
void OpenGLDisplayPlugin::stop() {
@ -216,19 +238,27 @@ void OpenGLDisplayPlugin::stop() {
}
void OpenGLDisplayPlugin::deactivate() {
#if THREADED_PRESENT
{
Lock lock(_mutex);
_deactivateWait.wait(lock, [&]{ return _uncustomized; });
}
_timer.stop();
#else
static auto widget = _container->getPrimaryWidget();
widget->makeCurrent();
uncustomizeContext();
_container->makeRenderingContextCurrent();
#endif
DisplayPlugin::deactivate();
}
void OpenGLDisplayPlugin::customizeContext() {
#if THREADED_PRESENT
_uncustomized = false;
auto presentThread = DependencyManager::get<PresentThread>();
Q_ASSERT(thread() == presentThread->thread());
#endif
enableVsync();
using namespace oglplus;
@ -297,16 +327,23 @@ void OpenGLDisplayPlugin::submitSceneTexture(uint32_t frameIndex, uint32_t scene
// Submit it to the presentation thread via escrow
_sceneTextureEscrow.submit(sceneTexture);
#if THREADED_PRESENT
#else
static auto widget = _container->getPrimaryWidget();
widget->makeCurrent();
present();
_container->makeRenderingContextCurrent();
#endif
}
void OpenGLDisplayPlugin::submitOverlayTexture(GLuint sceneTexture, const glm::uvec2& sceneSize) {
void OpenGLDisplayPlugin::submitOverlayTexture(GLuint overlayTexture, const glm::uvec2& overlaySize) {
// Submit it to the presentation thread via escrow
_overlayTextureEscrow.submit(sceneTexture);
_currentOverlayTexture = overlayTexture;
}
void OpenGLDisplayPlugin::updateTextures() {
_currentSceneTexture = _sceneTextureEscrow.fetchAndRelease(_currentSceneTexture);
_currentOverlayTexture = _overlayTextureEscrow.fetchAndRelease(_currentOverlayTexture);
}
void OpenGLDisplayPlugin::updateFramerate() {
@ -337,6 +374,11 @@ void OpenGLDisplayPlugin::present() {
internalPresent();
updateFramerate();
}
#if THREADED_PRESENT
#else
emit requestRender();
#endif
}
float OpenGLDisplayPlugin::presentRate() {
@ -351,12 +393,8 @@ float OpenGLDisplayPlugin::presentRate() {
}
void OpenGLDisplayPlugin::drawUnitQuad() {
try {
_program->Bind();
_plane->Draw();
} catch (const oglplus::Error& error) {
qWarning() << "The present thread encountered an error writing the scene texture to the output: " << error.what();
}
_program->Bind();
_plane->Draw();
}
void OpenGLDisplayPlugin::enableVsync(bool enable) {
@ -385,9 +423,16 @@ void OpenGLDisplayPlugin::swapBuffers() {
}
void OpenGLDisplayPlugin::withMainThreadContext(std::function<void()> f) const {
#if THREADED_PRESENT
static auto presentThread = DependencyManager::get<PresentThread>();
presentThread->withMainThreadContext(f);
_container->makeRenderingContextCurrent();
#else
static auto widget = _container->getPrimaryWidget();
widget->makeCurrent();
f();
_container->makeRenderingContextCurrent();
#endif
}
QImage OpenGLDisplayPlugin::getScreenshot() const {
@ -399,8 +444,10 @@ QImage OpenGLDisplayPlugin::getScreenshot() const {
return result;
}
#if THREADED_PRESENT
void OpenGLDisplayPlugin::enableDeactivate() {
Lock lock(_mutex);
_uncustomized = true;
_deactivateWait.notify_one();
}
}
#endif

View file

@ -18,6 +18,8 @@
#include <gl/OglplusHelpers.h>
#include <gl/GLEscrow.h>
#define THREADED_PRESENT 1
class OpenGLDisplayPlugin : public DisplayPlugin {
protected:
using Mutex = std::mutex;
@ -45,8 +47,9 @@ public:
virtual QImage getScreenshot() const override;
protected:
#if THREADED_PRESENT
friend class PresentThread;
#endif
virtual glm::uvec2 getSurfaceSize() const = 0;
virtual glm::uvec2 getSurfacePixels() const = 0;
@ -81,15 +84,16 @@ protected:
GLuint _currentSceneTexture { 0 };
GLuint _currentOverlayTexture { 0 };
GLTextureEscrow _overlayTextureEscrow;
GLTextureEscrow _sceneTextureEscrow;
bool _vsyncSupported { false };
private:
#if THREADED_PRESENT
void enableDeactivate();
Condition _deactivateWait;
bool _uncustomized{ false };
#endif
};