Currently job artifacts in CI/CD pipelines on LRZ GitLab never expire. Starting from Wed 26.1.2022 the default expiration time will be 30 days (GitLab default). Currently existing 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 725f577a authored by schultezub's avatar schultezub
Browse files

* removed QtThreadedPainter and implemented its functionality in TumVisPainter

 * QtContextManager uses QtThreadedCanvas
 * cleaned up tgt


git-svn-id: https://camplinux.in.tum.de/svn/campvis/trunk@198 bb408c1c-ae56-11e1-83d9-df6b3e0c105e
parent a503bd11
......@@ -18,9 +18,6 @@ SliceVis* sliceVis = 0;
TumVisPainter* painter = 0;
PipelineEvaluator* pe;
void startPainter() {
painter->run();
}
/**
* TUMVis main function, application entry point
*
......@@ -31,8 +28,8 @@ void startPainter() {
int main(int argc, char** argv) {
tgt::QtApplication* app = new tgt::QtApplication(argc, argv);
tgt::QtContextManager::init();
tgt::QtCanvas* renderCanvas = CtxtMgr.createContext("render", "TUMVis");
tgt::QtCanvas* sliceVisCanvas = CtxtMgr.createContext("sliceVis", "SliceVis");
tgt::QtThreadedCanvas* renderCanvas = CtxtMgr.createContext("render", "TUMVis");
tgt::QtThreadedCanvas* sliceVisCanvas = CtxtMgr.createContext("sliceVis", "SliceVis");
tbb::task_scheduler_init init;
renderCanvas->getContext()->acquire();
......@@ -75,14 +72,12 @@ int main(int argc, char** argv) {
pe = new PipelineEvaluator(sliceVis);
pe->start();
std::thread painterThread(&startPainter);
painter->start();
app->run();
painter->stop();
pe->stop();
painterThread.join();
painter->stop();
sliceVis->deinit();
painter->deinit();
......
......@@ -2,7 +2,9 @@
#include "tgt/assert.h"
#include "tgt/camera.h"
#include "tgt/glcontext.h"
#include "tgt/qt/qtthreadedcanvas.h"
#include "tgt/qt/qtglcontext.h"
#include "tgt/qt/qtcontextmanager.h"
#include "tgt/quadrenderer.h"
#include "tgt/quadric.h"
......@@ -11,21 +13,52 @@
namespace TUMVis {
const std::string TumVisPainter::loggerCat_ = "TUMVis.core.TumVisPainter";
TumVisPainter::TumVisPainter(tgt::QtCanvas* canvas, VisualizationPipeline* pipeline)
: tgt::QtThreadedPainter(canvas)
TumVisPainter::TumVisPainter(tgt::QtThreadedCanvas* canvas, VisualizationPipeline* pipeline)
: Runnable()
, tgt::Painter(canvas)
, _pipeline(0)
, _dirty(0)
, _currentlyRendering(false)
, _copyShader(0)
{
tgtAssert(getCanvas() != 0, "The given canvas must not be 0!");
_dirty = true;
setPipeline(pipeline);
}
TumVisPainter::~TumVisPainter() {
}
void TumVisPainter::stop() {
// we need to execute run() one more time to ensure correct release of the OpenGL context
_stopExecution = true;
_renderCondition.notify_all();
Runnable::stop();
}
void TumVisPainter::run() {
std::unique_lock<tbb::mutex> lock(CtxtMgr.getGlMutex());
while (! _stopExecution) {
getCanvas()->getContext()->acquire();
paint();
getCanvas()->swap();
while (!_stopExecution && !_dirty)
_renderCondition.wait(lock);
}
// release OpenGL context, so that other threads can access it
CtxtMgr.releaseCurrentContext();
}
void TumVisPainter::paint() {
if (getCanvas() == 0)
return;
while (_dirty) {
_dirty = false;
const tgt::ivec2& size = getCanvas()->getSize();
glViewport(0, 0, size.x, size.y);
......@@ -49,7 +82,6 @@ namespace TUMVis {
tgt::QuadRenderer::renderQuad();
_copyShader->deactivate();
LGL_ERROR;
}
else {
// TODO: render some nifty error texture
......@@ -78,13 +110,7 @@ namespace TUMVis {
errorTex_->disable();*/
}
LGL_ERROR;
{
tbb::mutex::scoped_lock lock(_localMutex);
_currentlyRendering = false;
}
if (_dirty)
getCanvas()->repaint();
}
void TumVisPainter::sizeChanged(const tgt::ivec2& size) {
......@@ -114,16 +140,23 @@ namespace TUMVis {
}
_pipeline = pipeline;
_pipeline->s_renderTargetChanged.connect(this, &TumVisPainter::onPipelineInvalidated);
_pipeline->s_renderTargetChanged.connect(this, &TumVisPainter::onRenderTargetChanged);
_pipeline->setRenderTargetSize(getCanvas()->getSize());
if (getCanvas()->getEventHandler() != 0)
getCanvas()->getEventHandler()->addListenerToFront(_pipeline);
}
void TumVisPainter::onPipelineInvalidated() {
void TumVisPainter::onRenderTargetChanged() {
// TODO: What happens, if the mutex is still acquired?
// Will the render thread woken up as soon as it is released?
_renderCondition.wakeAll();
if (!_stopExecution) {
_dirty = true;
_renderCondition.notify_all();
}
}
void TumVisPainter::setCanvas(tgt::GLCanvas* canvas) {
tgtAssert(dynamic_cast<tgt::QtThreadedCanvas*>(canvas) != 0, "Canvas must be of type QtThreadedCanvas!");
Painter::setCanvas(canvas);
}
}
\ No newline at end of file
#include "sigslot/sigslot.h"
#include "tbb/include/tbb/mutex.h"
#include "tbb/include/tbb/atomic.h"
#include "tbb/include/tbb/compat/condition_variable"
#include "tgt/logmanager.h"
#include "tgt/glcanvas.h"
#include "tgt/qt/qtthreadedpainter.h"
#include "tgt/event/eventhandler.h"
#include "tgt/painter.h"
#include "core/tools/runnable.h"
#include "core/pipeline/visualizationpipeline.h"
namespace tgt {
class Shader;
class QtThreadedCanvas;
}
namespace TUMVis {
/**
* Painter class for TUMVis
* Painter class for TUMVis, rendering the render target of a VisualizationPipeline.
* This painter implements Runnable, hence, it runs in its own thread and the associated canvas
* must be of type QtThreadedCanvas.
* Rendering is implemented using condidional wait - hence the canvas is only updated when
* \a pipeline emits the s_RenderTargetChanged signal.
*
* \todo
* \sa Runnable, VisualizationPipeline
*/
class TumVisPainter : public tgt::QtThreadedPainter, public sigslot::has_slots<> {
class TumVisPainter : public Runnable, public tgt::Painter, public sigslot::has_slots<> {
public:
TumVisPainter(tgt::QtCanvas* canvas, VisualizationPipeline* pipeline);
/**
* Creates a new TumVisPainter rendering the render target of \a pipeline on \a canvas.
* \param canvas Canvas to render on
* \param pipeline Pipeline to render
*/
TumVisPainter(tgt::QtThreadedCanvas* canvas, VisualizationPipeline* pipeline);
/**
* Destructor, stops and waits for the rendering thread if it's still running.
*/
virtual ~TumVisPainter();
/// \see Runnable::stop
void stop();
/**
* Performs the rendering using conditional wait.
* \sa Runnable::run
*/
void run();
/**
* Performs the actual rendering of the pipeline's render target
*/
virtual void paint();
/// \see tgt::Painter::sizeChanged
virtual void sizeChanged(const tgt::ivec2& size);
/**
* Initializes the painter, i.e. loads the OpenGL shader.
*/
virtual void init();
/**
* Deinitializes the painter, i.e. disposes its shader.
*/
virtual void deinit();
/**
* Sets the target canvas for rendering
* \param canvas Canvas to render on, must be of type QtThreadedCanvas
*/
virtual void setCanvas(tgt::GLCanvas* canvas);
/**
* Pipeline with the render target to render.
* \param pipeline Pipeline to render
*/
void setPipeline(VisualizationPipeline* pipeline);
void onPipelineInvalidated();
/**
* Slot being notified when the pipeline's render target changed.
*/
void onRenderTargetChanged();
private:
static const std::string loggerCat_;
VisualizationPipeline* _pipeline;
bool _dirty;
bool _currentlyRendering;
VisualizationPipeline* _pipeline; ///< Pipeline to render
tgt::Shader* _copyShader; ///< Shader for copying the render target to the framebuffer.
tbb::mutex _localMutex;
tbb::atomic<bool> _dirty; ///< Flag whether render result is dirty and needs to be rerendered.
std::condition_variable _renderCondition; ///< conditional wait condition for rendering
};
}
......@@ -29,8 +29,10 @@ namespace TUMVis {
}
void PipelineEvaluator::stop() {
// we need to execute run() one more time to ensure correct release of the OpenGL context
_stopExecution = true;
_evaluationCondition.notify_all();
Runnable::stop();
}
......
......@@ -4,9 +4,7 @@
#include "sigslot/sigslot.h"
#include "core/pipeline/abstractpipeline.h"
#include "core/tools/runnable.h"
#include "tbb/include/tbb/compat/thread"
#include "tbb/include/tbb/compat/condition_variable"
#include "tbb/include/tbb/atomic.h"
namespace TUMVis {
......@@ -14,6 +12,7 @@ namespace TUMVis {
* The PipelineEvaluator evaluates its pipeline in its own thread.
* Evaluation is implemented using condidional wait - hence the pipeline is only evaluated when
* \a pipeline emits the s_PipelineInvalidated signal.
*
* \sa Runnable
*/
class PipelineEvaluator : public Runnable, public sigslot::has_slots<> {
......@@ -27,7 +26,7 @@ namespace TUMVis {
/**
* Destructor, stops and waits for the evaluation thread if it's still running.
*/
~PipelineEvaluator();
virtual ~PipelineEvaluator();
/// \see Runnable::stop
void stop();
......
......@@ -21,6 +21,7 @@ namespace TUMVis {
void Runnable::stop() {
_stopExecution = true;
try {
if (_thread.joinable())
_thread.join();
}
catch(std::exception& e) {
......
......@@ -75,7 +75,6 @@ SET(TGT_SOURCES
qt/qtcontextmanager.cpp
qt/qtglcontext.cpp
qt/qtthreadedcanvas.cpp
qt/qtthreadedpainter.cpp
qt/qttimer.cpp
)
......
......@@ -65,13 +65,6 @@ public:
*/
~QtCanvas();
// override Qt events so that they don't interfere with the threading.
void resizeEvent(QResizeEvent *event) {
sizeChanged(ivec2(event->size().width(), event->size().height()));
};
void paintEvent(QPaintEvent *event) {};
/// initialize canvas
virtual void init();
......
......@@ -16,14 +16,15 @@ namespace tgt {
_contexts.clear();
}
QtCanvas* 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*/, QWidget* parent /*= 0*/, bool shared /*= true*/, Qt::WFlags f /*= 0*/, char* name /*= 0*/)
QtThreadedCanvas* 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*/, QWidget* parent /*= 0*/, bool shared /*= true*/, Qt::WFlags f /*= 0*/, char* name /*= 0*/)
{
tgtAssert(_contexts.find(key) == _contexts.end(), "A context with the same key already exists!");
QtCanvas* toReturn = new QtCanvas(title, size, buffers, parent, shared, f, name);
QtThreadedCanvas* toReturn = new QtThreadedCanvas(title, size, buffers, parent, shared, f, name);
_contexts.insert(std::make_pair(key, toReturn));
toReturn->makeCurrent();
// Init GLEW for this context
GLenum err = glewInit();
if (err != GLEW_OK) {
// Problem: glewInit failed, something is seriously wrong.
......@@ -75,7 +76,7 @@ namespace tgt {
_glMutex.unlock();
}
QMutex& QtContextManager::getGlMutex() {
tbb::mutex& QtContextManager::getGlMutex() {
return _glMutex;
}
......
......@@ -2,9 +2,9 @@
#define QTGLCONTEXTMANAGER_H__
#include "tgt/singleton.h"
#include "tgt/qt/qtcanvas.h"
#include "tgt/qt/qtthreadedcanvas.h"
#include "tgt/qt/qtglcontext.h"
#include <qmutex.h>
#include "tbb/include/tbb/mutex.h" // TODO: TBB dependency in TGT is not that beautiful...
#include <map>
#include <string>
......@@ -14,7 +14,7 @@ namespace tgt {
* Manages multiple shared OpenGL contexts and offers methods to ensure that only one context is active at a time.
*
*/
class TGT_API QtContextManager : public Singleton<QtContextManager> {
class QtContextManager : public Singleton<QtContextManager> {
friend class QtGLContext;
public:
......@@ -31,8 +31,8 @@ namespace tgt {
/**
* Creates a new OpenGL context in a QtCanvas with the given arguments.
* Parameters are the same as in QtCanvas() but context sharing is enables per default.
* 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.
* The newly created context will be active, but the OpenGL mutex not be locked.
*
* \note The created canvas/context is owned by this ContextManager. Hence, you may not
......@@ -41,9 +41,9 @@ namespace tgt {
* \param key Key of the context to create, must be unique.
* \param title Window title
* \param size Window size
* \return The newly created QtCanvas.
* \return The newly created QtThreadedCanvas.
*/
QtCanvas* createContext(
QtThreadedCanvas* createContext(
const std::string& key,
const std::string& title = "",
const ivec2& size = ivec2(GLCanvas::DEFAULT_WINDOW_WIDTH, GLCanvas::DEFAULT_WINDOW_HEIGHT),
......@@ -57,7 +57,7 @@ namespace tgt {
*/
QtGLContext* getContextByKey(const std::string& key);
QMutex& getGlMutex();
tbb::mutex& getGlMutex();
void releaseCurrentContext();
......@@ -84,7 +84,7 @@ namespace tgt {
std::map<std::string, QtCanvas*> _contexts; ///< Map of all OpenGL contexts
QtGLContext* _currentContext; ///< Current active OpenGL context
QMutex _glMutex; ///< Mutex protecting OpenGL for multi-threaded access
tbb::mutex _glMutex; ///< Mutex protecting OpenGL for multi-threaded access
};
} // namespace tgt
......
#include "qtthreadedcanvas.h"
#include "tgt/assert.h"
#include "tgt/qt/qtthreadedpainter.h"
namespace tgt {
......@@ -9,53 +8,20 @@ namespace tgt {
{
}
QtThreadedCanvas::~QtThreadedCanvas() {
}
void QtThreadedCanvas::startRendering() {
if (painter_ != 0) {
QtThreadedPainter* painter = static_cast<QtThreadedPainter*>(painter_);
painter->start();
}
}
void QtThreadedCanvas::stopRendering() {
if (painter_ != 0) {
QtThreadedPainter* painter = static_cast<QtThreadedPainter*>(painter_);
painter->stop();
painter->wait();
}
}
void QtThreadedCanvas::resizeGL(int w, int h) {
if (painter_ != 0) {
painter_->sizeChanged(ivec2(w, h));
}
}
void QtThreadedCanvas::paintGL() {
// all painting done in QtThreadedPainter
// all painting done in threaded painter
}
void QtThreadedCanvas::repaint() {
// all painting done in QtThreadedPainter
}
void QtThreadedCanvas::closeEvent(QCloseEvent *evt) {
stopRendering();
QtCanvas::closeEvent(evt);
// all painting done in threaded painter
}
void QtThreadedCanvas::paint() {
// all painting done in QtThreadedPainter
}
void QtThreadedCanvas::setPainter(Painter* p, bool initPainter /* = true */) {
tgtAssert(dynamic_cast<QtThreadedPainter*>(p) != 0, "Painter must be of type QtThreadedPainter!");
GLCanvas::setPainter(p, initPainter);
// all painting done in threaded painter
}
}
......@@ -20,20 +20,13 @@ namespace tgt {
~QtThreadedCanvas();
virtual void setPainter(tgt::Painter* p, bool initPainter = true);
void startRendering();
void stopRendering();
// override Qt events so that they don't interfere with the threading.
void resizeEvent(QResizeEvent *event) {
sizeChanged(ivec2(event->size().width(), event->size().height()));
};
/**
* This is called by the Qt framework every time the canvas is resized.
* This function calls the corresponding GLCanvas method \a sizeChanged.
*
* @param w The new width of the canvas.
* @param h The new height of the canvas.
*/
virtual void resizeGL(int w, int h);
// override Qt events so that they don't interfere with the threading.
void paintEvent(QPaintEvent *event) { };
/**
* Called by Qt if there is a paint event; it uses the \a painter_ to paint() something.
......@@ -50,8 +43,6 @@ namespace tgt {
*/
virtual void repaint();
virtual void closeEvent(QCloseEvent *evt);
protected:
};
......
#include "qtthreadedpainter.h"
#include "tgt/qt/qtcanvas.h"
#include "tgt/qt/qtthreadedcanvas.h"
#include "tgt/qt/qtcontextmanager.h"
namespace tgt {
QtThreadedPainter::QtThreadedPainter(QtCanvas* canvas)
: QThread()
, tgt::Painter(canvas)
{
_evaluateRenderingLoop = true;
}
void QtThreadedPainter::stop() {
_evaluateRenderingLoop = false;
_renderCondition.wakeAll();
}
void QtThreadedPainter::run() {
QtGLContext* qtContext = static_cast<QtCanvas*>(getCanvas())->getContext();
GLContextScopedLock lock(qtContext);
LGL_ERROR;
while (_evaluateRenderingLoop) {
paint();
glFlush();
qtContext->getCanvas()->swap();
/*if (qtContext->getCanvas()->doubleBuffer()) {
if (d->autoSwap)
swapBuffers();
} else {
glFlush();
}*/
// suspend rendering thread until there is again sth. to render.
_renderCondition.wait(&CtxtMgr.getGlMutex());
qtContext->acquire();
}
// release OpenGL context, so that other threads can access it
CtxtMgr.releaseCurrentContext();
}
void QtThreadedPainter::setCanvas(GLCanvas* canvas) {
tgtAssert(dynamic_cast<QtCanvas*>(canvas) != 0, "Context must be of type QtGLContext!");
Painter::setCanvas(canvas);
}
}
#ifndef QTTHREADEDPAINTER_H__
#define QTTHREADEDPAINTER_H__
#include "tgt/painter.h"
#include <qthread.h>
#include <qsize.h>
#include <qwaitcondition.h>
namespace tgt {
class QtCanvas;
/**
* Implementation of a tgt::Painter that runs in its own thread.
*/
class TGT_API QtThreadedPainter : public QThread, public tgt::Painter {
public:
QtThreadedPainter(QtCanvas* canvas);
void run();
void stop();
virtual void paint() = 0;
/// Set the context in which painter will draw
virtual void setCanvas(GLCanvas* canvas);
protected:
bool _evaluateRenderingLoop;
int rotAngle;
QWaitCondition _renderCondition;
};
}
#endif // QTTHREADEDPAINTER_H__
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment