Refactoring present thread / GL base plugin for saner context management

This commit is contained in:
Brad Davis 2015-12-03 15:39:09 -08:00
parent d8bb9f8d18
commit 7262a10e62
6 changed files with 42 additions and 69 deletions

View file

@ -26,17 +26,17 @@ DisplayPluginList getDisplayPlugins() {
DisplayPlugin* PLUGIN_POOL[] = { DisplayPlugin* PLUGIN_POOL[] = {
new Basic2DWindowOpenGLDisplayPlugin(), new Basic2DWindowOpenGLDisplayPlugin(),
new NullDisplayPlugin(), new NullDisplayPlugin(),
//#ifdef DEBUG #ifdef DEBUG
//#endif #endif
//
// // Stereo modes // Stereo modes
//
// // SBS left/right // SBS left/right
// new SideBySideStereoDisplayPlugin(), new SideBySideStereoDisplayPlugin(),
// // Interleaved left/right // Interleaved left/right
// new InterleavedStereoDisplayPlugin(), new InterleavedStereoDisplayPlugin(),
//
// // HMDs // HMDs
//#ifdef Q_OS_WIN //#ifdef Q_OS_WIN
// // SteamVR SDK // // SteamVR SDK
// new OpenVrDisplayPlugin(), // new OpenVrDisplayPlugin(),

View file

@ -28,8 +28,6 @@ class PresentThread : public QThread, public Dependency {
using Mutex = std::mutex; using Mutex = std::mutex;
using Condition = std::condition_variable; using Condition = std::condition_variable;
using Lock = std::unique_lock<Mutex>; using Lock = std::unique_lock<Mutex>;
friend class OpenGLDisplayPlugin;
public: public:
~PresentThread() { ~PresentThread() {
@ -42,6 +40,14 @@ public:
_newPlugin = plugin; _newPlugin = plugin;
} }
void setContext(QGLContext * context) {
// Move the OpenGL context to the present thread
// Extra code because of the widget 'wrapper' context
_context = context;
_context->moveToThread(this);
_context->contextHandle()->moveToThread(this);
}
virtual void run() override { virtual void run() override {
Q_ASSERT(_context); Q_ASSERT(_context);
while (!_shutdown) { while (!_shutdown) {
@ -50,7 +56,7 @@ public:
Lock lock(_mutex); Lock lock(_mutex);
// Move the context to the main thread // Move the context to the main thread
_context->moveToThread(qApp->thread()); _context->moveToThread(qApp->thread());
_widgetContext->moveToThread(qApp->thread()); _context->contextHandle()->moveToThread(qApp->thread());
_pendingMainThreadOperation = false; _pendingMainThreadOperation = false;
// Release the main thread to do it's action // Release the main thread to do it's action
_condition.notify_one(); _condition.notify_one();
@ -67,6 +73,7 @@ public:
// Check before lock // Check before lock
if (_newPlugin != nullptr) { if (_newPlugin != nullptr) {
Lock lock(_mutex); Lock lock(_mutex);
_context->makeCurrent();
// Check if we have a new plugin to activate // Check if we have a new plugin to activate
if (_newPlugin != nullptr) { if (_newPlugin != nullptr) {
// Deactivate the old plugin // Deactivate the old plugin
@ -77,8 +84,8 @@ public:
_newPlugin->customizeContext(); _newPlugin->customizeContext();
_activePlugin = _newPlugin; _activePlugin = _newPlugin;
_newPlugin = nullptr; _newPlugin = nullptr;
_context->doneCurrent();
} }
_context->doneCurrent();
lock.unlock(); lock.unlock();
} }
@ -89,12 +96,14 @@ public:
} }
// take the latest texture and present it // take the latest texture and present it
_context->makeCurrent();
_activePlugin->present(); _activePlugin->present();
_context->doneCurrent();
} }
_context->doneCurrent(); _context->doneCurrent();
_widgetContext->moveToThread(qApp->thread());
_context->moveToThread(qApp->thread()); _context->moveToThread(qApp->thread());
_context->contextHandle()->moveToThread(qApp->thread());
} }
void withMainThreadContext(std::function<void()> f) { void withMainThreadContext(std::function<void()> f) {
@ -104,14 +113,16 @@ public:
_finishedMainThreadOperation = false; _finishedMainThreadOperation = false;
_condition.wait(lock, [&] { return !_pendingMainThreadOperation; }); _condition.wait(lock, [&] { return !_pendingMainThreadOperation; });
_widgetContext->makeCurrent(); _context->makeCurrent();
f(); f();
_widgetContext->doneCurrent(); _context->doneCurrent();
// Move the context back to the presentation thread
_context->moveToThread(this);
_context->contextHandle()->moveToThread(this);
// restore control of the context to the presentation thread and signal // restore control of the context to the presentation thread and signal
// the end of the operation // the end of the operation
_widgetContext->moveToThread(this);
_context->moveToThread(this);
_finishedMainThreadOperation = true; _finishedMainThreadOperation = true;
lock.unlock(); lock.unlock();
_condition.notify_one(); _condition.notify_one();
@ -119,6 +130,9 @@ public:
private: private:
void makeCurrent();
void doneCurrent();
bool _shutdown { false }; bool _shutdown { false };
Mutex _mutex; Mutex _mutex;
// Used to allow the main thread to perform context operations // Used to allow the main thread to perform context operations
@ -128,8 +142,7 @@ private:
QThread* _mainThread { nullptr }; QThread* _mainThread { nullptr };
OpenGLDisplayPlugin* _newPlugin { nullptr }; OpenGLDisplayPlugin* _newPlugin { nullptr };
OpenGLDisplayPlugin* _activePlugin { nullptr }; OpenGLDisplayPlugin* _activePlugin { nullptr };
QOpenGLContext* _context { nullptr }; QGLContext* _context { nullptr };
QGLContext* _widgetContext { nullptr };
}; };
OpenGLDisplayPlugin::OpenGLDisplayPlugin() { OpenGLDisplayPlugin::OpenGLDisplayPlugin() {
@ -165,16 +178,8 @@ void OpenGLDisplayPlugin::activate() {
DependencyManager::set<PresentThread>(); DependencyManager::set<PresentThread>();
presentThread = DependencyManager::get<PresentThread>(); presentThread = DependencyManager::get<PresentThread>();
presentThread->setObjectName("Presentation Thread"); presentThread->setObjectName("Presentation Thread");
auto widget = _container->getPrimaryWidget(); auto widget = _container->getPrimaryWidget();
presentThread->setContext(widget->context());
// Move the OpenGL context to the present thread
// Extra code because of the widget 'wrapper' context
presentThread->_widgetContext = widget->context();
presentThread->_widgetContext->moveToThread(presentThread.data());
presentThread->_context = presentThread->_widgetContext->contextHandle();
presentThread->_context->moveToThread(presentThread.data());
// Start execution // Start execution
presentThread->start(); presentThread->start();
} }
@ -196,9 +201,6 @@ void OpenGLDisplayPlugin::customizeContext() {
auto presentThread = DependencyManager::get<PresentThread>(); auto presentThread = DependencyManager::get<PresentThread>();
Q_ASSERT(thread() == presentThread->thread()); Q_ASSERT(thread() == presentThread->thread());
bool makeCurrentResult = makeCurrent();
Q_ASSERT(makeCurrentResult);
// TODO: write the proper code for linux // TODO: write the proper code for linux
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
_vsyncSupported = wglewGetExtension("WGL_EXT_swap_control"); _vsyncSupported = wglewGetExtension("WGL_EXT_swap_control");
@ -213,15 +215,11 @@ void OpenGLDisplayPlugin::customizeContext() {
_program = loadDefaultShader(); _program = loadDefaultShader();
_plane = loadPlane(_program); _plane = loadPlane(_program);
doneCurrent();
} }
void OpenGLDisplayPlugin::uncustomizeContext() { void OpenGLDisplayPlugin::uncustomizeContext() {
makeCurrent();
_program.reset(); _program.reset();
_plane.reset(); _plane.reset();
doneCurrent();
} }
// Pressing Alt (and Meta) key alone activates the menubar because its style inherits the // Pressing Alt (and Meta) key alone activates the menubar because its style inherits the
@ -310,19 +308,11 @@ void OpenGLDisplayPlugin::internalPresent() {
} }
void OpenGLDisplayPlugin::present() { void OpenGLDisplayPlugin::present() {
auto makeCurrentResult = makeCurrent();
Q_ASSERT(makeCurrentResult);
if (!makeCurrentResult) {
qDebug() << "Failed to make current";
return;
}
updateTextures(); updateTextures();
if (_currentSceneTexture) { if (_currentSceneTexture) {
internalPresent(); internalPresent();
updateFramerate(); updateFramerate();
} }
doneCurrent();
} }
float OpenGLDisplayPlugin::presentRate() { float OpenGLDisplayPlugin::presentRate() {
@ -360,18 +350,6 @@ bool OpenGLDisplayPlugin::isVsyncEnabled() {
return true; return true;
#endif #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() { void OpenGLDisplayPlugin::swapBuffers() {
static auto widget = _container->getPrimaryWidget(); static auto widget = _container->getPrimaryWidget();

View file

@ -63,8 +63,6 @@ protected:
void updateTextures(); void updateTextures();
void updateFramerate(); void updateFramerate();
void drawUnitQuad(); void drawUnitQuad();
bool makeCurrent();
void doneCurrent();
void swapBuffers(); void swapBuffers();
// Plugin specific functionality to composite the scene and overlay and present the result // Plugin specific functionality to composite the scene and overlay and present the result
virtual void internalPresent(); virtual void internalPresent();

View file

@ -67,5 +67,9 @@ glm::uvec2 InterleavedStereoDisplayPlugin::getRecommendedRenderSize() const {
} }
void InterleavedStereoDisplayPlugin::internalPresent() { void InterleavedStereoDisplayPlugin::internalPresent() {
// FIXME using namespace oglplus;
_program->Bind();
auto sceneSize = getRecommendedRenderSize();
Uniform<ivec2>(*_program, "textureSize").SetValue(sceneSize);
WindowOpenGLDisplayPlugin::internalPresent();
} }

View file

@ -55,11 +55,9 @@ bool OculusBaseDisplayPlugin::isSupported() const {
// DLL based display plugins MUST initialize GLEW inside the DLL code. // DLL based display plugins MUST initialize GLEW inside the DLL code.
void OculusBaseDisplayPlugin::customizeContext() { void OculusBaseDisplayPlugin::customizeContext() {
makeCurrent();
glewExperimental = true; glewExperimental = true;
GLenum err = glewInit(); GLenum err = glewInit();
glGetError(); glGetError();
doneCurrent();
WindowOpenGLDisplayPlugin::customizeContext(); WindowOpenGLDisplayPlugin::customizeContext();
} }

View file

@ -154,8 +154,6 @@ void OculusDisplayPlugin::activate() {
void OculusDisplayPlugin::customizeContext() { void OculusDisplayPlugin::customizeContext() {
OculusBaseDisplayPlugin::customizeContext(); OculusBaseDisplayPlugin::customizeContext();
bool makeCurrentResult = makeCurrent();
Q_ASSERT(makeCurrentResult);
#if (OVR_MAJOR_VERSION >= 6) #if (OVR_MAJOR_VERSION >= 6)
_sceneFbo = SwapFboPtr(new SwapFramebufferWrapper(_hmd)); _sceneFbo = SwapFboPtr(new SwapFramebufferWrapper(_hmd));
_sceneFbo->Init(getRecommendedRenderSize()); _sceneFbo->Init(getRecommendedRenderSize());
@ -169,14 +167,11 @@ void OculusDisplayPlugin::customizeContext() {
enableVsync(false); enableVsync(false);
// Only enable mirroring if we know vsync is disabled // Only enable mirroring if we know vsync is disabled
_enablePreview = !isVsyncEnabled(); _enablePreview = !isVsyncEnabled();
doneCurrent();
} }
void OculusDisplayPlugin::uncustomizeContext() { void OculusDisplayPlugin::uncustomizeContext() {
#if (OVR_MAJOR_VERSION >= 6) #if (OVR_MAJOR_VERSION >= 6)
makeCurrent();
_sceneFbo.reset(); _sceneFbo.reset();
doneCurrent();
#endif #endif
OculusBaseDisplayPlugin::uncustomizeContext(); OculusBaseDisplayPlugin::uncustomizeContext();
} }