The expiration time for new job artifacts in CI/CD pipelines is now 30 days (GitLab default). Previously generated artifacts in already completed jobs will not be affected by the change. The latest artifacts for all jobs in the latest successful pipelines will be kept. More information: https://gitlab.lrz.de/help/user/admin_area/settings/continuous_integration.html#default-artifacts-expiration

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__
#include "tgt/singleton.h"
#include "tgt/glcontextmanager.h"