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 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; ...@@ -18,9 +18,6 @@ SliceVis* sliceVis = 0;
TumVisPainter* painter = 0; TumVisPainter* painter = 0;
PipelineEvaluator* pe; PipelineEvaluator* pe;
void startPainter() {
painter->run();
}
/** /**
* TUMVis main function, application entry point * TUMVis main function, application entry point
* *
...@@ -31,8 +28,8 @@ void startPainter() { ...@@ -31,8 +28,8 @@ void startPainter() {
int main(int argc, char** argv) { int main(int argc, char** argv) {
tgt::QtApplication* app = new tgt::QtApplication(argc, argv); tgt::QtApplication* app = new tgt::QtApplication(argc, argv);
tgt::QtContextManager::init(); tgt::QtContextManager::init();
tgt::QtCanvas* renderCanvas = CtxtMgr.createContext("render", "TUMVis"); tgt::QtThreadedCanvas* renderCanvas = CtxtMgr.createContext("render", "TUMVis");
tgt::QtCanvas* sliceVisCanvas = CtxtMgr.createContext("sliceVis", "SliceVis"); tgt::QtThreadedCanvas* sliceVisCanvas = CtxtMgr.createContext("sliceVis", "SliceVis");
tbb::task_scheduler_init init; tbb::task_scheduler_init init;
renderCanvas->getContext()->acquire(); renderCanvas->getContext()->acquire();
...@@ -75,14 +72,12 @@ int main(int argc, char** argv) { ...@@ -75,14 +72,12 @@ int main(int argc, char** argv) {
pe = new PipelineEvaluator(sliceVis); pe = new PipelineEvaluator(sliceVis);
pe->start(); pe->start();
std::thread painterThread(&startPainter); painter->start();
app->run(); app->run();
painter->stop();
pe->stop(); pe->stop();
painter->stop();
painterThread.join();
sliceVis->deinit(); sliceVis->deinit();
painter->deinit(); painter->deinit();
......
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
#include "tgt/assert.h" #include "tgt/assert.h"
#include "tgt/camera.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/quadrenderer.h"
#include "tgt/quadric.h" #include "tgt/quadric.h"
...@@ -11,80 +13,104 @@ ...@@ -11,80 +13,104 @@
namespace TUMVis { namespace TUMVis {
const std::string TumVisPainter::loggerCat_ = "TUMVis.core.TumVisPainter"; const std::string TumVisPainter::loggerCat_ = "TUMVis.core.TumVisPainter";
TumVisPainter::TumVisPainter(tgt::QtCanvas* canvas, VisualizationPipeline* pipeline) TumVisPainter::TumVisPainter(tgt::QtThreadedCanvas* canvas, VisualizationPipeline* pipeline)
: tgt::QtThreadedPainter(canvas) : Runnable()
, tgt::Painter(canvas)
, _pipeline(0) , _pipeline(0)
, _dirty(0)
, _currentlyRendering(false)
, _copyShader(0) , _copyShader(0)
{ {
tgtAssert(getCanvas() != 0, "The given canvas must not be 0!"); tgtAssert(getCanvas() != 0, "The given canvas must not be 0!");
_dirty = true;
setPipeline(pipeline); setPipeline(pipeline);
} }
void TumVisPainter::paint() { TumVisPainter::~TumVisPainter() {
if (getCanvas() == 0)
return;
const tgt::ivec2& size = getCanvas()->getSize(); }
glViewport(0, 0, size.x, size.y);
// try get Data
const ImageDataRenderTarget* image = _pipeline->getRenderTarget();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (image != 0) {
// activate shader
_copyShader->activate();
_copyShader->setIgnoreUniformLocationError(true);
_copyShader->setUniform("_viewportSize", size);
_copyShader->setUniform("_viewportSizeRCP", 1.f / tgt::vec2(size));
_copyShader->setIgnoreUniformLocationError(false);
// bind input textures
tgt::TextureUnit colorUnit, depthUnit;
image->bind(_copyShader, colorUnit, depthUnit);
LGL_ERROR;
// execute the shader void TumVisPainter::stop() {
tgt::QuadRenderer::renderQuad(); // we need to execute run() one more time to ensure correct release of the OpenGL context
_copyShader->deactivate(); _stopExecution = true;
LGL_ERROR; _renderCondition.notify_all();
} Runnable::stop();
else { }
// TODO: render some nifty error texture
// so long, we do some dummy rendering
tgt::Camera c(tgt::vec3(0.f,0.f,2.f));
c.look();
glColor3f(1.f, 0.f, 0.f);
tgt::Sphere sphere(.5f, 64, 32);
sphere.render();
/*
// render error texture
if (!errorTex_) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
return;
}
glClear(GL_DEPTH_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0); void TumVisPainter::run() {
errorTex_->bind(); std::unique_lock<tbb::mutex> lock(CtxtMgr.getGlMutex());
errorTex_->enable();
glColor3f(1.f, 1.f, 1.f); while (! _stopExecution) {
renderQuad(); getCanvas()->getContext()->acquire();
paint();
getCanvas()->swap();
errorTex_->disable();*/ while (!_stopExecution && !_dirty)
_renderCondition.wait(lock);
} }
LGL_ERROR;
{ // release OpenGL context, so that other threads can access it
tbb::mutex::scoped_lock lock(_localMutex); CtxtMgr.releaseCurrentContext();
_currentlyRendering = false; }
void TumVisPainter::paint() {
if (getCanvas() == 0)
return;
while (_dirty) {
_dirty = false;
const tgt::ivec2& size = getCanvas()->getSize();
glViewport(0, 0, size.x, size.y);
// try get Data
const ImageDataRenderTarget* image = _pipeline->getRenderTarget();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (image != 0) {
// activate shader
_copyShader->activate();
_copyShader->setIgnoreUniformLocationError(true);
_copyShader->setUniform("_viewportSize", size);
_copyShader->setUniform("_viewportSizeRCP", 1.f / tgt::vec2(size));
_copyShader->setIgnoreUniformLocationError(false);
// bind input textures
tgt::TextureUnit colorUnit, depthUnit;
image->bind(_copyShader, colorUnit, depthUnit);
LGL_ERROR;
// execute the shader
tgt::QuadRenderer::renderQuad();
_copyShader->deactivate();
LGL_ERROR;
}
else {
// TODO: render some nifty error texture
// so long, we do some dummy rendering
tgt::Camera c(tgt::vec3(0.f,0.f,2.f));
c.look();
glColor3f(1.f, 0.f, 0.f);
tgt::Sphere sphere(.5f, 64, 32);
sphere.render();
/*
// render error texture
if (!errorTex_) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
return;
}
glClear(GL_DEPTH_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
errorTex_->bind();
errorTex_->enable();
glColor3f(1.f, 1.f, 1.f);
renderQuad();
errorTex_->disable();*/
}
LGL_ERROR;
} }
if (_dirty)
getCanvas()->repaint();
} }
void TumVisPainter::sizeChanged(const tgt::ivec2& size) { void TumVisPainter::sizeChanged(const tgt::ivec2& size) {
...@@ -114,16 +140,23 @@ namespace TUMVis { ...@@ -114,16 +140,23 @@ namespace TUMVis {
} }
_pipeline = pipeline; _pipeline = pipeline;
_pipeline->s_renderTargetChanged.connect(this, &TumVisPainter::onPipelineInvalidated); _pipeline->s_renderTargetChanged.connect(this, &TumVisPainter::onRenderTargetChanged);
_pipeline->setRenderTargetSize(getCanvas()->getSize()); _pipeline->setRenderTargetSize(getCanvas()->getSize());
if (getCanvas()->getEventHandler() != 0) if (getCanvas()->getEventHandler() != 0)
getCanvas()->getEventHandler()->addListenerToFront(_pipeline); getCanvas()->getEventHandler()->addListenerToFront(_pipeline);
} }
void TumVisPainter::onPipelineInvalidated() { void TumVisPainter::onRenderTargetChanged() {
// TODO: What happens, if the mutex is still acquired? // TODO: What happens, if the mutex is still acquired?
// Will the render thread woken up as soon as it is released? // 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 "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/logmanager.h"
#include "tgt/glcanvas.h" #include "tgt/painter.h"
#include "tgt/qt/qtthreadedpainter.h"
#include "tgt/event/eventhandler.h"
#include "core/tools/runnable.h"
#include "core/pipeline/visualizationpipeline.h" #include "core/pipeline/visualizationpipeline.h"
namespace tgt { namespace tgt {
class Shader; class Shader;
class QtThreadedCanvas;
} }
namespace TUMVis { 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: 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);
virtual void paint(); /**
* 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); virtual void sizeChanged(const tgt::ivec2& size);
/**
* Initializes the painter, i.e. loads the OpenGL shader.
*/
virtual void init(); virtual void init();
/**
* Deinitializes the painter, i.e. disposes its shader.
*/
virtual void deinit(); 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 setPipeline(VisualizationPipeline* pipeline);
void onPipelineInvalidated();
/**
* Slot being notified when the pipeline's render target changed.
*/
void onRenderTargetChanged();
private: private:
static const std::string loggerCat_; static const std::string loggerCat_;
VisualizationPipeline* _pipeline; VisualizationPipeline* _pipeline; ///< Pipeline to render
bool _dirty;
bool _currentlyRendering;
tgt::Shader* _copyShader; ///< Shader for copying the render target to the framebuffer. 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 { ...@@ -29,8 +29,10 @@ namespace TUMVis {
} }
void PipelineEvaluator::stop() { void PipelineEvaluator::stop() {
// we need to execute run() one more time to ensure correct release of the OpenGL context
_stopExecution = true; _stopExecution = true;
_evaluationCondition.notify_all(); _evaluationCondition.notify_all();
Runnable::stop(); Runnable::stop();
} }
......
...@@ -4,9 +4,7 @@ ...@@ -4,9 +4,7 @@
#include "sigslot/sigslot.h" #include "sigslot/sigslot.h"
#include "core/pipeline/abstractpipeline.h" #include "core/pipeline/abstractpipeline.h"
#include "core/tools/runnable.h" #include "core/tools/runnable.h"
#include "tbb/include/tbb/compat/thread"
#include "tbb/include/tbb/compat/condition_variable" #include "tbb/include/tbb/compat/condition_variable"
#include "tbb/include/tbb/atomic.h"
namespace TUMVis { namespace TUMVis {
...@@ -14,6 +12,7 @@ namespace TUMVis { ...@@ -14,6 +12,7 @@ namespace TUMVis {
* The PipelineEvaluator evaluates its pipeline in its own thread. * The PipelineEvaluator evaluates its pipeline in its own thread.
* Evaluation is implemented using condidional wait - hence the pipeline is only evaluated when * Evaluation is implemented using condidional wait - hence the pipeline is only evaluated when
* \a pipeline emits the s_PipelineInvalidated signal. * \a pipeline emits the s_PipelineInvalidated signal.
*
* \sa Runnable * \sa Runnable
*/ */
class PipelineEvaluator : public Runnable, public sigslot::has_slots<> { class PipelineEvaluator : public Runnable, public sigslot::has_slots<> {
...@@ -27,7 +26,7 @@ namespace TUMVis { ...@@ -27,7 +26,7 @@ namespace TUMVis {
/** /**
* Destructor, stops and waits for the evaluation thread if it's still running. * Destructor, stops and waits for the evaluation thread if it's still running.
*/ */
~PipelineEvaluator(); virtual ~PipelineEvaluator();
/// \see Runnable::stop /// \see Runnable::stop
void stop(); void stop();
......
...@@ -21,7 +21,8 @@ namespace TUMVis { ...@@ -21,7 +21,8 @@ namespace TUMVis {
void Runnable::stop() { void Runnable::stop() {
_stopExecution = true; _stopExecution = true;
try { try {
_thread.join(); if (_thread.joinable())
_thread.join();
} }
catch(std::exception& e) { catch(std::exception& e) {
LERRORC("TUMVis.core.tools.Runnable", "Caught exception during _thread.join: " << e.what()); LERRORC("TUMVis.core.tools.Runnable", "Caught exception during _thread.join: " << e.what());
......
...@@ -75,7 +75,6 @@ SET(TGT_SOURCES ...@@ -75,7 +75,6 @@ SET(TGT_SOURCES
qt/qtcontextmanager.cpp qt/qtcontextmanager.cpp
qt/qtglcontext.cpp qt/qtglcontext.cpp
qt/qtthreadedcanvas.cpp qt/qtthreadedcanvas.cpp
qt/qtthreadedpainter.cpp
qt/qttimer.cpp qt/qttimer.cpp
) )
......
...@@ -65,13 +65,6 @@ public: ...@@ -65,13 +65,6 @@ public:
*/ */
~QtCanvas(); ~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 /// initialize canvas
virtual void init(); virtual void init();
......
...@@ -16,14 +16,15 @@ namespace tgt { ...@@ -16,14 +16,15 @@ namespace tgt {
_contexts.clear(); _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!"); 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)); _contexts.insert(std::make_pair(key, toReturn));
toReturn->makeCurrent(); toReturn->makeCurrent();
// Init GLEW for this context
GLenum err = glewInit(); GLenum err = glewInit();
if (err != GLEW_OK) { if (err != GLEW_OK) {
// Problem: glewInit failed, something is seriously wrong. // Problem: glewInit failed, something is seriously wrong.
...@@ -75,7 +76,7 @@ namespace tgt { ...@@ -75,7 +76,7 @@ namespace tgt {
_glMutex.unlock(); _glMutex.unlock();
} }
QMutex& QtContextManager::getGlMutex() { tbb::mutex& QtContextManager::getGlMutex() {
return _glMutex; return _glMutex;
} }
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
#define QTGLCONTEXTMANAGER_H__ #define QTGLCONTEXTMANAGER_H__
#include "tgt/singleton.h" #include "tgt/singleton.h"
#include "tgt/qt/qtcanvas.h" #include "tgt/qt/qtthreadedcanvas.h"
#include "tgt/qt/qtglcontext.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 <map>
#include <string> #include <string>
...@@ -14,7 +14,7 @@ namespace tgt { ...@@ -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. * 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; friend class QtGLContext;
public: public:
...@@ -31,8 +31,8 @@ namespace tgt { ...@@ -31,8 +31,8 @@ namespace tgt {
/** /**
* Creates a new OpenGL context in a QtCanvas with the given arguments. * Creates a new OpenGL context in a QtThreadedCanvas with the given arguments.
* Parameters are the same as in QtCanvas() but context sharing is enables per default. * 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. * 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 * \note The created canvas/context is owned by this ContextManager. Hence, you may not
...@@ -41,9 +41,9 @@ namespace tgt { ...@@ -41,9 +41,9 @@ namespace tgt {
* \param key Key of the context to create, must be unique.