Commit e009adbb authored by Christian Schulte zu Berge's avatar Christian Schulte zu Berge
Browse files

Fixed tgt::GlContextManager being abstract and thus not able to behave as singleton:

Removed oblivious tgt::QtContextManager and merged functionality into tgt::GLCanvas and tgt::GlContextManager. Meanwhile, improved OpenGL context initialization and pipeline creation in CampvisApplication.
parent 8beb8280
......@@ -27,11 +27,11 @@
#include "tgt/assert.h"
#include "tgt/exception.h"
#include "tgt/glcanvas.h"
#include "tgt/glcontextmanager.h"
#include "tgt/gpucapabilities.h"
#include "tgt/shadermanager.h"
#include "tgt/qt/qtapplication.h"
#include "tgt/qt/qtthreadedcanvas.h"
#include "tgt/qt/qtcontextmanager.h"
#include "tbb/compat/thread"
#include "application/campvispainter.h"
......@@ -61,7 +61,7 @@ namespace campvis {
QApplication::setAttribute(Qt::AA_X11InitThreads);
_mainWindow = new MainWindow(this);
tgt::QtContextManager::init();
tgt::GlContextManager::init();
OpenGLJobProcessor::init();
SimpleJobProcessor::init();
......@@ -85,23 +85,14 @@ namespace campvis {
void CampVisApplication::init() {
tgtAssert(_initialized == false, "Tried to initialize CampVisApplication twice.");
// parse argument list and create pipelines
QStringList pipelinesToAdd = this->arguments();
for (int i = 1; i < pipelinesToAdd.size(); ++i) {
DataContainer* dc = createAndAddDataContainer("DataContainer #" + StringUtils::toString(_dataContainers.size() + 1));
AbstractPipeline* p = PipelineFactory::getRef().createPipeline(pipelinesToAdd[i].toStdString(), dc);
if (p != 0)
addPipeline(pipelinesToAdd[i].toStdString(), p);
}
// Init TGT
tgt::InitFeature::Features featureset = tgt::InitFeature::ALL;
tgt::init(featureset);
LogMgr.getConsoleLog()->addCat("", true);
// create a local OpenGL context and init GL
_localContext = tgt::GlContextManager::getRef().createContext("AppContext", "", tgt::ivec2(16, 16));
tgtAssert(_localContext != 0, "Could not create local OpenGL context");
_localContext = new QtThreadedCanvas("", tgt::ivec2(16, 16));
tgt::GlContextManager::getRef().registerContextAndInitGlew(_localContext);
tgt::GLContextScopedLock lock(_localContext);
......@@ -143,18 +134,18 @@ namespace campvis {
LERROR("Your system does not support GLSL Shader Version 3.30, which is mandatory. CAMPVis will probably not work as intended.");
}
// init pipeline first
for (std::vector<AbstractPipeline*>::iterator it = _pipelines.begin(); it != _pipelines.end(); ++it) {
(*it)->init();
}
GLJobProc.start();
GLJobProc.registerContext(_localContext);
// Now init painters:
for (std::vector< std::pair<AbstractPipeline*, CampVisPainter*> >::iterator it = _visualizations.begin(); it != _visualizations.end(); ++it) {
it->second->init();
// parse argument list and create pipelines
QStringList pipelinesToAdd = this->arguments();
for (int i = 1; i < pipelinesToAdd.size(); ++i) {
DataContainer* dc = createAndAddDataContainer("DataContainer #" + StringUtils::toString(_dataContainers.size() + 1));
AbstractPipeline* p = PipelineFactory::getRef().createPipeline(pipelinesToAdd[i].toStdString(), dc);
if (p != 0)
addPipeline(pipelinesToAdd[i].toStdString(), p);
}
GLJobProc.start();
GLJobProc.registerContext(_localContext);
_initialized = true;
}
......@@ -188,7 +179,7 @@ namespace campvis {
OpenGLJobProcessor::deinit();
PipelineFactory::deinit();
tgt::QtContextManager::deinit();
tgt::GlContextManager::deinit();
tgt::deinit();
// MainWindow dtor needs a valid CampVisApplication, so we need to call it here instead of during destruction.
......@@ -214,30 +205,8 @@ namespace campvis {
void CampVisApplication::addPipeline(const std::string& name, AbstractPipeline* pipeline) {
tgtAssert(pipeline != 0, "Pipeline must not be 0.");
// if CAMPVis is already fully initialized, we need to temporarily shut down its
// OpenGL job processor, since we need to create a new context.
if (_initialized) {
GLJobProc.pause();
{
tgt::QtThreadedCanvas* canvas = dynamic_cast<tgt::QtThreadedCanvas*>(tgt::GlContextManager::getRef().createContext(name, "CAMPVis", tgt::ivec2(512, 512)));
tgtAssert(canvas != 0, "Dynamic cast failed. This should not be the case, since we initialized the GlContextManager singleton with a QtContextManager.");
tgt::GLContextScopedLock lock(canvas);
addPipelineImpl(canvas, name, pipeline);
}
GLJobProc.resume();
}
else {
tgt::QtThreadedCanvas* canvas = dynamic_cast<tgt::QtThreadedCanvas*>(tgt::GlContextManager::getRef().createContext(name, "CAMPVis", tgt::ivec2(512, 512)));
tgtAssert(canvas != 0, "Dynamic cast failed. This should not be the case, since we initialized the GlContextManager singleton with a QtContextManager.");
addPipelineImpl(canvas, name, pipeline);
}
s_PipelinesChanged();
}
void CampVisApplication::addPipelineImpl(tgt::QtThreadedCanvas* canvas, const std::string& name, AbstractPipeline* pipeline) {
// create canvas and painter for the pipeline and connect all together
tgt::QtThreadedCanvas* canvas = new tgt::QtThreadedCanvas("CAMPVis", tgt::ivec2(512, 512));
GLJobProc.registerContext(canvas);
canvas->init();
......@@ -248,17 +217,25 @@ namespace campvis {
_visualizations.push_back(std::make_pair(pipeline, painter));
_pipelines.push_back(pipeline);
if (_initialized) {
LGL_ERROR;
pipeline->init();
LGL_ERROR;
painter->init();
LGL_ERROR;
}
tgt::GlContextManager::getRef().releaseCurrentContext();
_mainWindow->addVisualizationPipelineWidget(name, canvas);
// initialize context (GLEW) and pipeline in OpenGL thread)
GLJobProc.enqueueJob(
canvas,
makeJobOnHeap<CampVisApplication, tgt::GLCanvas*, AbstractPipeline*>(this, &CampVisApplication::initGlContextAndPipeline, canvas, pipeline),
OpenGLJobProcessor::SerialJob);
s_PipelinesChanged();
}
void CampVisApplication::initGlContextAndPipeline(tgt::GLCanvas* canvas, AbstractPipeline* pipeline) {
tgt::GlContextManager::getRef().registerContextAndInitGlew(canvas);
pipeline->init();
LGL_ERROR;
canvas->getPainter()->init();
LGL_ERROR;
// enable pipeline and invalidate all processors
pipeline->setEnabled(true);
for (std::vector<AbstractProcessor*>::const_iterator it = pipeline->getProcessors().begin(); it != pipeline->getProcessors().end(); ++it) {
......
......@@ -130,7 +130,8 @@ namespace campvis {
sigslot::signal0<> s_DataContainersChanged;
private:
void addPipelineImpl(tgt::QtThreadedCanvas* canvas, const std::string& name, AbstractPipeline* pipeline);
void initGlContextAndPipeline(tgt::GLCanvas* canvas, AbstractPipeline* pipeline);
/// All pipelines
std::vector<AbstractPipeline*> _pipelines;
......
......@@ -29,7 +29,7 @@
#include "tgt/painter.h"
#include "tgt/event/eventlistener.h"
#include "tgt/event/mouseevent.h"
#include "tgt/qt/qtcontextmanager.h"
#include "tgt/glcontextmanager.h"
#include "tgt/qt/qtthreadedcanvas.h"
#include "tbb/mutex.h"
......
......@@ -29,8 +29,6 @@
#include "tgt/filesystem.h"
#include "tgt/shadermanager.h"
#include "tgt/textureunit.h"
#include "tgt/qt/qtcontextmanager.h"
#include "tgt/qt/qtthreadedcanvas.h"
#ifdef CAMPVIS_HAS_MODULE_DEVIL
#include <IL/il.h>
......@@ -53,7 +51,7 @@
#include "application/gui/datacontainertreewidget.h"
#include "application/gui/qtdatahandle.h"
#include "application//gui/datacontainerfileloaderwidget.h"
#include "application/gui/datacontainerfileloaderwidget.h"
#include "modules/io/processors/genericimagereader.h"
#include <QFileDialog>
......
......@@ -27,8 +27,6 @@
#include "sigslot/sigslot.h"
#include "tgt/painter.h"
#include "tgt/qt/qtcontextmanager.h"
#include "tgt/qt/qtthreadedcanvas.h"
#include "tbb/mutex.h"
#include "application/gui/qtdatahandle.h"
......
......@@ -27,8 +27,6 @@
#include "sigslot/sigslot.h"
#include "tgt/painter.h"
#include "tgt/qt/qtcontextmanager.h"
#include "tgt/qt/qtthreadedcanvas.h"
#include "tbb/mutex.h"
#include "application/tools/bufferinglog.h"
......
......@@ -248,8 +248,8 @@ namespace campvis {
QLabel* lblOpacityBottom = new QLabel(tr("0%"), this);
_layout->addWidget(lblOpacityBottom, 3, 0, 1, 1, Qt::AlignRight);
_canvas = dynamic_cast<tgt::QtThreadedCanvas*>(tgt::GlContextManager::getRef().createContext("tfcanvas", "", tgt::ivec2(256, 128), tgt::GLCanvas::RGBA_BUFFER, false));
tgtAssert(_canvas != 0, "Could not cast to QtThreadedCanvas*, something is wrong here!");
_canvas = new tgt::QtThreadedCanvas("", tgt::ivec2(256, 128), tgt::GLCanvas::RGBA_BUFFER, false);
tgt::GlContextManager::getRef().registerContextAndInitGlew(_canvas);
GLJobProc.registerContext(_canvas);
_canvas->setPainter(this, false);
......
......@@ -229,8 +229,8 @@ namespace campvis {
QLabel* lblOpacityBottom = new QLabel(tr("0%"), this);
_layout->addWidget(lblOpacityBottom, 3, 0, 1, 1, Qt::AlignRight);
_canvas = dynamic_cast<tgt::QtThreadedCanvas*>(tgt::GlContextManager::getRef().createContext("tfcanvas ", "", tgt::ivec2(256, 128), tgt::GLCanvas::RGBA_BUFFER, false));
tgtAssert(_canvas != 0, "Could not cast to QtThreadedCanvas*, something is wrong here!");
_canvas = new tgt::QtThreadedCanvas("", tgt::ivec2(256, 128), tgt::GLCanvas::RGBA_BUFFER, false);
tgt::GlContextManager::getRef().registerContextAndInitGlew(_canvas);
GLJobProc.registerContext(_canvas);
_canvas->setPainter(this, false);
......
......@@ -74,14 +74,12 @@ IF(TGT_WITH_QT)
LIST(APPEND TGT_HEADERS
qt/qtapplication.h
qt/qtcanvas.h
qt/qtcontextmanager.h
qt/qtthreadedcanvas.h
qt/qttimer.h)
LIST(APPEND TGT_SOURCES
qt/qtapplication.cpp
qt/qtcanvas.cpp
qt/qtcontextmanager.cpp
qt/qtthreadedcanvas.cpp
qt/qttimer.cpp)
ENDIF(TGT_WITH_QT)
......
......@@ -194,6 +194,11 @@ public:
/// Getter
bool isInitialized() const { return initialized_; }
/// Acqures this canvas as current context
virtual void acquireAsCurrentContext() = 0;
/// Releases this canvas as current context
virtual void releaseAsCurrentContext() = 0;
protected:
/// Use the painter_ to actually paint something on the canvas
......
......@@ -3,9 +3,7 @@
#include "tgt/assert.h"
namespace tgt {
GlContextManager* GlContextManager::singletonClass_ = 0;
GlContextManager::GlContextManager()
: _currentContext(0)
{
......@@ -13,22 +11,12 @@ namespace tgt {
GlContextManager::~GlContextManager()
{
for (std::map<std::string, GLCanvas*>::iterator it = _contexts.begin(); it != _contexts.end(); ++it) {
delete it->second;
for (std::set<GLCanvas*>::iterator it = _contexts.begin(); it != _contexts.end(); ++it) {
delete *it;
}
_contexts.clear();
}
GLCanvas* GlContextManager::getContextByKey(const std::string& key) {
tbb::mutex::scoped_lock lock(_localMutex);
std::map<std::string, GLCanvas*>::iterator it = _contexts.find(key);
if (it != _contexts.end())
return it->second;
else
return 0;
}
void GlContextManager::lock() {
_glMutex.lock();
}
......@@ -51,20 +39,6 @@ namespace tgt {
return _currentContext;
}
GlContextManager* GlContextManager::getPtr() {
tgtAssert( singletonClass_ != 0, "singletonClass_ has not been intitialized." );
return singletonClass_;
}
GlContextManager& GlContextManager::getRef() {
tgtAssert( singletonClass_ != 0 , "singletonClass_ has not been intitialized." );
return *singletonClass_;
}
bool GlContextManager::isInited() {
return (singletonClass_ != 0);
}
void GlContextManager::lockAndAcquire(GLCanvas* context) {
lock();
setCurrent(context);
......@@ -79,16 +53,52 @@ namespace tgt {
setCurrent(context);
}
void GlContextManager::registerContextAndInitGlew(GLCanvas* context) {
tgtAssert(context != 0, "Given context must not be 0.");
tgtAssert(_contexts.find(context) == _contexts.end(), "Tried to double register the same context.");
{
tbb::mutex::scoped_lock localLock(_localMutex);
_contexts.insert(context);
}
// Init GLEW for this context
GLenum err = glewInit();
if (err != GLEW_OK) {
// Problem: glewInit failed, something is seriously wrong.
tgtAssert(false, "glewInit failed");
std::cerr << "glewInit failed, error: " << glewGetErrorString(err) << std::endl;
exit(EXIT_FAILURE);
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
}
void GlContextManager::removeContext(GLCanvas* context) {
_currentContext = 0;
tbb::mutex::scoped_lock lock(_localMutex);
for (std::map<std::string, GLCanvas*>::iterator it = _contexts.begin(); it != _contexts.end(); ++it) {
if (it->second == context) {
_contexts.erase(it);
break;
std::set<GLCanvas*>::iterator it = _contexts.find(context);
if (it != _contexts.end()) {
_contexts.erase(it);
}
}
void GlContextManager::setCurrent(GLCanvas* context) {
if (_currentContext != context) {
if (context == 0) {
// explicitely release OpenGL context
_currentContext->releaseAsCurrentContext();
_currentContext = 0;
}
else {
context->acquireAsCurrentContext();
LGL_ERROR;
_currentContext = context;
}
}
}
}
......@@ -5,11 +5,9 @@
#include "tgt/glcanvas.h"
#include "tgt/types.h"
#include <tbb/mutex.h> // TODO: TBB dependency in TGT is not that beautiful...
#include <map>
#include <set>
#include <string>
class QWidget;
namespace tgt {
class GLCanvas;
......@@ -30,68 +28,50 @@ namespace tgt {
virtual ~GlContextManager();
/**
* Get Pointer of the actual class
* @return Pointer of the actual class
*/
static GlContextManager* getPtr();
/**
* Get reference of the actual class
* @return reference of the actual class
*/
static GlContextManager& getRef();
/**
* Has the actual class been inited?
* Registers \a canvas as new managed OpenGL context and initializes GLEW.
* \param canvas OpenGL context to register
*/
static bool isInited();
/**
* Creates a new OpenGL context in a QtThreadedCanvas with the given arguments.
* Parameters are the same as in QtThreadedCanvas() but context sharing is enables per default.
*
* \note Must be called with the OpenGL mutex acquired!
*
* \note The created canvas/context is owned by this ContextManager. Hence, you may not
* delete it yourself!
*
* \param key Key of the context to create, must be unique.
* \param title Window title
* \param size Window size
* \return The newly created QtThreadedCanvas.
*/
virtual GLCanvas* createContext(
const std::string& key,
const std::string& title = "",
const ivec2& size = ivec2(GLCanvas::DEFAULT_WINDOW_WIDTH, GLCanvas::DEFAULT_WINDOW_HEIGHT),
const GLCanvas::Buffers buffers = GLCanvas::RGBADD,
bool shared = true) = 0;
void registerContextAndInitGlew(GLCanvas* context);
/**
* Removes the OpenGL context \a context from the list of managed contexts.
* \param context Context to remove.
*/
virtual void removeContext(GLCanvas* context);
void removeContext(GLCanvas* context);
/**
* Returns the OpenGL context with the given key \a key, 0 if no such context exists.
* \param key Key of the context to return.
* \return The OpenGL context with the given key \a key, 0 if no such context exists.
* Returns the currently active OpenGL context.
* \return _currentContext
*/
GLCanvas* getContextByKey(const std::string& key);
GLCanvas* getCurrentContext() const;
/**
* Returns the mutex protecting the OpenGL context
* \return _glMutex
*/
tbb::mutex& getGlMutex();
/**
* Acquires \a context as current OpenGL context.
* \param context OpenGL context to acquire.
*/
void acquireContext(GLCanvas* context);
/**
* Releases the currently bound OpenGL context.
*/
void releaseCurrentContext();
/**
* Locks the OpenGL context mutex and acquires \a context as current OpenGl context.
* \param context OpenGL context to acquire.
*/
void lockAndAcquire(GLCanvas* context);
/**
* Releases the currently bound OpenGL context and also releases the OpenGL mutex.
*/
void releaseAndUnlock();
protected:
......@@ -100,7 +80,7 @@ namespace tgt {
* If \a context is already the current context, nothing will happen.
* \param context Context to set as current.
*/
virtual void setCurrent(GLCanvas* context) = 0;
void setCurrent(GLCanvas* context);
/**
* Locks the OpenGL device for other threads acessing the ContextManager.
......@@ -115,13 +95,11 @@ namespace tgt {
void unlock();
std::map<std::string, GLCanvas*> _contexts; ///< Map of all OpenGL contexts
std::set<GLCanvas*> _contexts; ///< Map of all OpenGL contexts
GLCanvas* _currentContext; ///< Current active OpenGL context
tbb::mutex _glMutex; ///< Mutex protecting OpenGL for multi-threaded access
tbb::mutex _localMutex; ///< local mutex to prodect _contexts
static GlContextManager* singletonClass_;
};
......
......@@ -574,5 +574,13 @@ QSize QtCanvas::sizeHint() const {
return QSize(size.x, size.y);
}
void QtCanvas::acquireAsCurrentContext() {
this->makeCurrent();
}
void QtCanvas::releaseAsCurrentContext() {
this->doneCurrent();
}
} // namespace
......@@ -111,6 +111,12 @@ public:
*/
virtual void update();
/// Acqures this canvas as current context
virtual void acquireAsCurrentContext();
/// Releases this canvas as current context
virtual void releaseAsCurrentContext();
/// swap buffers
virtual void swap();
......
#include "qtcontextmanager.h"
#include "tgt/assert.h"
namespace tgt {
QtContextManager::QtContextManager()
: GlContextManager()
{
}
QtContextManager::~QtContextManager()
{
}
GLCanvas* QtContextManager::createContext(const std::string& key, const std::string& title /*= ""*/, const ivec2& size /*= ivec2(DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT)*/, const GLCanvas::Buffers buffers /*= RGBADD*/, bool shared /*= true*/)
{
// FIXME: rethink this concept of unique IDs
//tgtAssert(_contexts.find(key) == _contexts.end(), "A context with the same key already exists!");
tbb::mutex::scoped_lock localLock(_localMutex);
tbb::mutex::scoped_lock lock(_glMutex);
QtThreadedCanvas* toReturn = new QtThreadedCanvas(title, size, buffers, 0, shared);
_contexts.insert(std::make_pair(key, toReturn));
toReturn->makeCurrent();
_currentContext = toReturn;
// Init GLEW for this context
GLenum err = glewInit();
if (err != GLEW_OK) {
// Problem: glewInit failed, something is seriously wrong.
tgtAssert(false, "glewInit failed");
std::cerr << "glewInit failed, error: " << glewGetErrorString(err) << std::endl;
exit(EXIT_FAILURE);
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
releaseCurrentContext();
return toReturn;
}
void QtContextManager::setCurrent(GLCanvas* context) {
if (_currentContext != context) {
if (context == 0) {
// explicitely release OpenGL context
static_cast<QtThreadedCanvas*>(_currentContext)->doneCurrent();
_currentContext = 0;
}
else {
static_cast<QtThreadedCanvas*>(context)->makeCurrent();
LGL_ERROR;
_currentContext = context;
}
}
}
void QtContextManager::init() {
tgtAssert( !singletonClass_, "singletonClass_ has already been initialized." );
singletonClass_ = new QtContextManager();
}
void QtContextManager::deinit() {
tgtAssert( singletonClass_ != 0, "singletonClass_ has already been deinitialized." );
delete singletonClass_;
singletonClass_ = 0;
}
}
#ifndef QTGLCONTEXTMANAGER_H__
#define QTGLCONTEXTMANAGER_H__