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,21 +13,52 @@ ...@@ -11,21 +13,52 @@
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);
} }
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() { void TumVisPainter::paint() {
if (getCanvas() == 0) if (getCanvas() == 0)
return; return;
while (_dirty) {
_dirty = false;
const tgt::ivec2& size = getCanvas()->getSize(); const tgt::ivec2& size = getCanvas()->getSize();
glViewport(0, 0, size.x, size.y); glViewport(0, 0, size.x, size.y);
...@@ -49,7 +82,6 @@ namespace TUMVis { ...@@ -49,7 +82,6 @@ namespace TUMVis {
tgt::QuadRenderer::renderQuad(); tgt::QuadRenderer::renderQuad();
_copyShader->deactivate(); _copyShader->deactivate();
LGL_ERROR; LGL_ERROR;
} }
else { else {
// TODO: render some nifty error texture // TODO: render some nifty error texture
...@@ -78,13 +110,7 @@ namespace TUMVis { ...@@ -78,13 +110,7 @@ namespace TUMVis {
errorTex_->disable();*/ errorTex_->disable();*/
} }
LGL_ERROR; LGL_ERROR;
{
tbb::mutex::scoped_lock lock(_localMutex);
_currentlyRendering = false;
} }
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);
/**
* 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(); 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,6 +21,7 @@ namespace TUMVis { ...@@ -21,6 +21,7 @@ namespace TUMVis {
void Runnable::stop() { void Runnable::stop() {
_stopExecution = true; _stopExecution = true;
try { try {
if (_thread.joinable())
_thread.join(); _thread.join();
} }
catch(std::exception& e) { catch(std::exception& e) {
......
...@@ -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. * \param key Key of the context to create, must be unique.
* \param title Window title * \param title Window title
* \param size Window size * \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& key,
const std::string& title = "", const std::string& title = "",
const ivec2& size = ivec2(GLCanvas::DEFAULT_WINDOW_WIDTH, GLCanvas::DEFAULT_WINDOW_HEIGHT), const ivec2& size = ivec2(GLCanvas::DEFAULT_WINDOW_WIDTH, GLCanvas::DEFAULT_WINDOW_HEIGHT),
...@@ -57,7 +57,7 @@ namespace tgt { ...@@ -57,7 +57,7 @@ namespace tgt {
*/ */
QtGLContext* getContextByKey(const std::string& key); QtGLContext* getContextByKey(const std::string& key);
QMutex& getGlMutex(); tbb::mutex& getGlMutex();
void releaseCurrentContext(); void releaseCurrentContext();
...@@ -84,7 +84,7 @@ namespace tgt { ...@@ -84,7 +84,7 @@ namespace tgt {
std::map<std::string, QtCanvas*> _contexts; ///< Map of all OpenGL contexts std::map<std::string, QtCanvas*> _contexts; ///< Map of all OpenGL contexts
QtGLContext* _currentContext; ///< Current active OpenGL context 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 } // namespace tgt
......
#include "qtthreadedcanvas.h" #include "qtthreadedcanvas.h"
#include "tgt/assert.h" #include "tgt/assert.h"
#include "tgt/qt/qtthreadedpainter.h"
namespace tgt { namespace tgt {
...@@ -9,53 +8,20 @@ namespace tgt { ...@@ -9,53 +8,20 @@ namespace tgt {
{ {
} }
QtThreadedCanvas::~QtThreadedCanvas() { 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();