Commit 4609c893 authored by schultezub's avatar schultezub
Browse files

* started implementing proper deinitialization of everything

 * added Runnable interface
 * started letting PipelineEvaluator manage its thread itself
 * documentation

git-svn-id: https://camplinux.in.tum.de/svn/campvis/trunk@196 bb408c1c-ae56-11e1-83d9-df6b3e0c105e
parent 1302ca97
...@@ -12,8 +12,6 @@ ...@@ -12,8 +12,6 @@
#include "core/pipeline/pipelineevaluator.h" #include "core/pipeline/pipelineevaluator.h"
#include "modules/pipelines/slicevis.h" #include "modules/pipelines/slicevis.h"
#include <functional>
using namespace TUMVis; using namespace TUMVis;
SliceVis* sliceVis = 0; SliceVis* sliceVis = 0;
...@@ -44,7 +42,6 @@ int main(int argc, char** argv) { ...@@ -44,7 +42,6 @@ int main(int argc, char** argv) {
tbb::task_scheduler_init init; tbb::task_scheduler_init init;
renderCanvas->getContext()->acquire(); renderCanvas->getContext()->acquire();
app->addCanvas(renderCanvas); app->addCanvas(renderCanvas);
//app->addCanvas(sliceVisCanvas);
app->init(); app->init();
LogMgr.getConsoleLog()->addCat("", true); LogMgr.getConsoleLog()->addCat("", true);
LGL_ERROR; LGL_ERROR;
...@@ -92,6 +89,12 @@ int main(int argc, char** argv) { ...@@ -92,6 +89,12 @@ int main(int argc, char** argv) {
evaluatorThread.join(); evaluatorThread.join();
painterThread.join(); painterThread.join();
sliceVis->deinit();
painter->deinit();
tgt::deinitGL();
tgt::QtContextManager::deinit();
tgt::deinit();
delete painter; delete painter;
delete sliceVis; delete sliceVis;
delete app; delete app;
......
...@@ -89,7 +89,6 @@ namespace TUMVis { ...@@ -89,7 +89,6 @@ namespace TUMVis {
void TumVisPainter::sizeChanged(const tgt::ivec2& size) { void TumVisPainter::sizeChanged(const tgt::ivec2& size) {
_pipeline->setRenderTargetSize(size); _pipeline->setRenderTargetSize(size);
_renderCondition.wakeAll();
} }
void TumVisPainter::init() { void TumVisPainter::init() {
...@@ -102,6 +101,10 @@ namespace TUMVis { ...@@ -102,6 +101,10 @@ namespace TUMVis {
} }
} }
void TumVisPainter::deinit() {
ShdrMgr.dispose(_copyShader);
}
void TumVisPainter::setPipeline(VisualizationPipeline* pipeline) { void TumVisPainter::setPipeline(VisualizationPipeline* pipeline) {
tgtAssert(pipeline != 0, "The given pipeline must not be 0."); tgtAssert(pipeline != 0, "The given pipeline must not be 0.");
if (_pipeline != 0) { if (_pipeline != 0) {
......
...@@ -26,6 +26,7 @@ namespace TUMVis { ...@@ -26,6 +26,7 @@ namespace TUMVis {
virtual void paint(); virtual void paint();
virtual void sizeChanged(const tgt::ivec2& size); virtual void sizeChanged(const tgt::ivec2& size);
virtual void init(); virtual void init();
virtual void deinit();
void setPipeline(VisualizationPipeline* pipeline); void setPipeline(VisualizationPipeline* pipeline);
void onPipelineInvalidated(); void onPipelineInvalidated();
......
...@@ -27,6 +27,18 @@ namespace TUMVis { ...@@ -27,6 +27,18 @@ namespace TUMVis {
} }
} }
void AbstractPipeline::deinit() {
// deinitialize all processors:
for (std::vector<AbstractProcessor*>::iterator it = _processors.begin(); it != _processors.end(); ++it) {
try {
(*it)->deinit();
}
catch (tgt::Exception& e) {
LERROR("Caught Exception during deinitialization of processor: " << e.what());
}
}
}
void AbstractPipeline::onNotify(const ProcessorObserverArgs& poa) { void AbstractPipeline::onNotify(const ProcessorObserverArgs& poa) {
_invalidationLevel.setLevel(InvalidationLevel::INVALID_RESULT); _invalidationLevel.setLevel(InvalidationLevel::INVALID_RESULT);
s_PipelineInvalidated(); s_PipelineInvalidated();
...@@ -42,10 +54,6 @@ namespace TUMVis { ...@@ -42,10 +54,6 @@ namespace TUMVis {
processor.unlockProperties(); processor.unlockProperties();
} }
tbb::mutex& AbstractPipeline::getEvaluationMutex() {
return _evaluationMutex;
}
InvalidationLevel& AbstractPipeline::getInvalidationLevel() { InvalidationLevel& AbstractPipeline::getInvalidationLevel() {
return _invalidationLevel; return _invalidationLevel;
} }
......
...@@ -15,12 +15,14 @@ ...@@ -15,12 +15,14 @@
#include <vector> #include <vector>
namespace TUMVis { namespace TUMVis {
class PipelineEvaluator;
/** /**
* Abstract base class for TUMVis Pipelines. * Abstract base class for TUMVis Pipelines.
* *
*/ */
class AbstractPipeline : public GenericObserver<ProcessorObserverArgs> { class AbstractPipeline : public GenericObserver<ProcessorObserverArgs> {
friend class PipelineEvaluator;
public: public:
/** /**
* Creates a AbstractPipeline. * Creates a AbstractPipeline.
...@@ -34,12 +36,19 @@ namespace TUMVis { ...@@ -34,12 +36,19 @@ namespace TUMVis {
/** /**
* Initializes the OpenGL context of the pipeline and its processors. * Initializes this pipeline and all of its processors.
* Everything that requires a valid OpenGL context or is otherwise expensive gets in here.
* *
* \note When overwriting this method, make sure to call the base class version first. * \note When overwriting this method, make sure to call the base class version first.
*/ */
virtual void init(); virtual void init();
/**
* Deinitializes this pipeline and all of its processors.
* \note When overwriting this method, make sure to call the base class version first.
*/
virtual void deinit();
/** /**
* Execute this pipeline. * Execute this pipeline.
**/ **/
...@@ -65,8 +74,6 @@ namespace TUMVis { ...@@ -65,8 +74,6 @@ namespace TUMVis {
*/ */
virtual void onNotify(const ProcessorObserverArgs& poa); virtual void onNotify(const ProcessorObserverArgs& poa);
tbb::mutex& getEvaluationMutex();
InvalidationLevel& getInvalidationLevel(); InvalidationLevel& getInvalidationLevel();
...@@ -85,7 +92,7 @@ namespace TUMVis { ...@@ -85,7 +92,7 @@ namespace TUMVis {
InvalidationLevel _invalidationLevel; ///< current invalidation level InvalidationLevel _invalidationLevel; ///< current invalidation level
tbb::spin_mutex _localMutex; ///< mutex for altering local members tbb::spin_mutex _localMutex; ///< mutex for altering local members
tbb::mutex _evaluationMutex; ///< mutex for the evaluation of this pipeline tbb::mutex _evaluationMutex; ///< mutex for the evaluation of this pipeline
static const std::string loggerCat_; static const std::string loggerCat_;
}; };
......
...@@ -34,9 +34,12 @@ namespace TUMVis { ...@@ -34,9 +34,12 @@ namespace TUMVis {
} }
void AbstractProcessor::init() { void AbstractProcessor::init() {
}
void AbstractProcessor::deinit() {
} }
void AbstractProcessor::lockProperties() { void AbstractProcessor::lockProperties() {
_properties.lockAllProperties(); _properties.lockAllProperties();
} }
......
...@@ -69,10 +69,18 @@ namespace TUMVis { ...@@ -69,10 +69,18 @@ namespace TUMVis {
/** /**
* Initializes the OpenGL context of the processor. * Initializes the processor.
* Everything that requires a valid OpenGL context or is otherwise expensive gets in here.
*
* \note When overwriting this method, make sure to call the base class version first. * \note When overwriting this method, make sure to call the base class version first.
*/ */
virtual void init(); virtual void init();
/**
* Deinitializes this processors.
* \note When overwriting this method, make sure to call the base class version first.
*/
virtual void deinit();
/** /**
* Execute this processor. * Execute this processor.
......
...@@ -6,19 +6,21 @@ namespace TUMVis { ...@@ -6,19 +6,21 @@ namespace TUMVis {
PipelineEvaluator::PipelineEvaluator(AbstractPipeline* pipeline) PipelineEvaluator::PipelineEvaluator(AbstractPipeline* pipeline)
: _pipeline(pipeline) : _pipeline(pipeline)
, _evaluatePipeline(false) , _evaluationThread()
{ {
tgtAssert(pipeline != 0, "Pipeline must not be 0."); tgtAssert(pipeline != 0, "Pipeline must not be 0.");
_evaluatePipeline = false;
pipeline->s_PipelineInvalidated.connect(this, &PipelineEvaluator::OnPipelineInvalidated); pipeline->s_PipelineInvalidated.connect(this, &PipelineEvaluator::OnPipelineInvalidated);
} }
PipelineEvaluator::~PipelineEvaluator() { PipelineEvaluator::~PipelineEvaluator() {
_pipeline->s_PipelineInvalidated.disconnect(this); _pipeline->s_PipelineInvalidated.disconnect(this);
} }
void PipelineEvaluator::startEvaluation() { void PipelineEvaluator::startEvaluation() {
_evaluatePipeline = true; _evaluatePipeline = true;
std::unique_lock<tbb::mutex> lock(_pipeline->getEvaluationMutex()); std::unique_lock<tbb::mutex> lock(_pipeline->_evaluationMutex);
while (_evaluatePipeline) { while (_evaluatePipeline) {
_pipeline->execute(); _pipeline->execute();
......
...@@ -3,12 +3,14 @@ ...@@ -3,12 +3,14 @@
#include "sigslot/sigslot.h" #include "sigslot/sigslot.h"
#include "core/pipeline/abstractpipeline.h" #include "core/pipeline/abstractpipeline.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 {
/** /**
* * The PipelineEvaluator
*/ */
class PipelineEvaluator : public sigslot::has_slots<> { class PipelineEvaluator : public sigslot::has_slots<> {
public: public:
...@@ -18,16 +20,18 @@ namespace TUMVis { ...@@ -18,16 +20,18 @@ namespace TUMVis {
void startEvaluation(); void startEvaluation();
void stopEvaluation(); void stopEvaluation();
void evaluate();
void OnPipelineInvalidated(); void OnPipelineInvalidated();
protected: protected:
AbstractPipeline* _pipeline; AbstractPipeline* _pipeline;
bool _evaluatePipeline; tbb::atomic<bool> _evaluatePipeline;
std::thread _evaluationThread;
std::condition_variable _evaluationCondition; std::condition_variable _evaluationCondition;
static const std::string loggerCat_; static const std::string loggerCat_;
......
...@@ -45,6 +45,11 @@ namespace TUMVis { ...@@ -45,6 +45,11 @@ namespace TUMVis {
AbstractPipeline::init(); AbstractPipeline::init();
} }
void VisualizationPipeline::deinit() {
tgt::GLContextScopedLock lock(_canvas->getContext());
AbstractPipeline::deinit();
}
const tgt::ivec2& VisualizationPipeline::getRenderTargetSize() const { const tgt::ivec2& VisualizationPipeline::getRenderTargetSize() const {
return _renderTargetSize.getValue(); return _renderTargetSize.getValue();
} }
...@@ -66,7 +71,7 @@ namespace TUMVis { ...@@ -66,7 +71,7 @@ namespace TUMVis {
void VisualizationPipeline::lockGLContextAndExecuteProcessor(AbstractProcessor& processor) { void VisualizationPipeline::lockGLContextAndExecuteProcessor(AbstractProcessor& processor) {
tgt::GLContextScopedLock lock(_canvas->getContext()); tgt::GLContextScopedLock lock(_canvas->getContext());
executeProcessor(processor); executeProcessor(processor);
glFlush(); glFlush(); // TODO: is glFlush enough or do we need a glFinish here?
} }
} }
...@@ -39,6 +39,12 @@ namespace TUMVis { ...@@ -39,6 +39,12 @@ namespace TUMVis {
*/ */
virtual void init(); virtual void init();
/**
* Deinitializes this pipeline and all of its processors.
* \note When overwriting this method, make sure to call the base class version first.
*/
virtual void deinit();
/** /**
* Execute this pipeline. * Execute this pipeline.
**/ **/
...@@ -86,7 +92,7 @@ namespace TUMVis { ...@@ -86,7 +92,7 @@ namespace TUMVis {
*/ */
void onDataContainerDataAdded(const std::string& name, const DataHandle* dh); void onDataContainerDataAdded(const std::string& name, const DataHandle* dh);
/// Signal emitted when the pipeline's render target has changed
sigslot::signal0<> s_renderTargetChanged; sigslot::signal0<> s_renderTargetChanged;
protected: protected:
......
...@@ -4,9 +4,10 @@ namespace TUMVis { ...@@ -4,9 +4,10 @@ namespace TUMVis {
VisualizationProcessor::VisualizationProcessor(GenericProperty<tgt::ivec2>& canvasSize) VisualizationProcessor::VisualizationProcessor(GenericProperty<tgt::ivec2>& canvasSize)
: AbstractProcessor() : AbstractProcessor()
, _canvasSize("canvasSize", "Canvas Size", canvasSize.getValue()) , _renderTargetSize("canvasSize", "Canvas Size", canvasSize.getValue())
{ {
canvasSize.addSharedProperty(&_canvasSize); canvasSize.addSharedProperty(&_renderTargetSize);
_renderTargetSize.addObserver(this);
} }
VisualizationProcessor::~VisualizationProcessor() { VisualizationProcessor::~VisualizationProcessor() {
......
...@@ -9,25 +9,25 @@ ...@@ -9,25 +9,25 @@
namespace TUMVis { namespace TUMVis {
/** /**
* Abstract base class for TUMVis Processors. * Specialization of AbstractProcessor for visualization purposes.
* A processor implements a specific task, which it performs on the DataCollection passed * VisualizationProcessors are required to be called by a VisualizationPipeline which ensure
* during process(). Properties provide a transparent layer for adjusting the processor's * to provide a valid OpenGL context when calling the processor's process() method. Hence, a
* behaviour. * VisualizationProcessor is allowed/capable of performing OpenGl operations.
* Once a processor has finished it sets it should set its invalidation level to valid. As * For determining the canvas/viewport size, a VisualizationProcessor gets a reference to the
* soon as one of its properties changes, the processor will be notified and possibliy * parent pipeline's render target size property during instantiation.
* change its invalidation level. Observing pipelines will be notified of this and can
* and have to decide which part of the pipeline has to be re-evaluated wrt. the processor's
* invalidation level.
* *
* \sa AbstractPipeline * \sa VisualizationPipeline
*/ */
class VisualizationProcessor : public AbstractProcessor { class VisualizationProcessor : public AbstractProcessor {
public: public:
/** /**
* Creates a VisualizationProcessor. * Creates a VisualizationProcessor.
* \note The render target size property of this VisualizationProcessor will automatically
* be assigned as shared property of the given \a renderTargetSize property.
* \param renderTargetSize Reference to the parent pipeline's render target size property.
*/ */
VisualizationProcessor(GenericProperty<tgt::ivec2>& canvasSize); VisualizationProcessor(GenericProperty<tgt::ivec2>& renderTargetSize);
/** /**
* Virtual Destructor * Virtual Destructor
...@@ -36,7 +36,7 @@ namespace TUMVis { ...@@ -36,7 +36,7 @@ namespace TUMVis {
protected: protected:
GenericProperty<tgt::ivec2> _canvasSize; ///< Viewport size of target canvas GenericProperty<tgt::ivec2> _renderTargetSize; ///< Viewport size of target canvas
}; };
} }
......
#ifndef RUNNABLE_H__
#define RUNNABLE_H__
#include "tgt/logmanager.h"
#include "tbb/include/tbb/compat/thread"
#include "tbb/include/tbb/atomic.h"
namespace TUMVis {
/**
* Abstract base class for objects that shall run in a separate thread.
*/
class Runnable {
public:
Runnable()
: _stopExecution()
, _thread()
{}
virtual ~Runnable() {
stop();
}
virtual void stop() {
_stopExecution = true;
try {
_thread.join();
}
catch(std::exception& e) {
LERRORC("TUMVis.core.tools.Runnable", "Caught exception during _thread.join: " << e.what());
}
}
void start() {
_thread = std::thread(&Runnable::run, *this);
}
protected:
virtual void run() = 0;
tbb::atomic<bool> _stopExecution;
private:
Runnable(Runnable const&) = delete;
Runnable& operator =(Runnable const&) = delete;
std::thread _thread;
};
}
#endif // RUNNABLE_H__
...@@ -67,7 +67,6 @@ public: ...@@ -67,7 +67,6 @@ public:
// override Qt events so that they don't interfere with the threading. // override Qt events so that they don't interfere with the threading.
void resizeEvent(QResizeEvent *event) { void resizeEvent(QResizeEvent *event) {
QWidget::resizeEvent(event);
sizeChanged(ivec2(event->size().width(), event->size().height())); sizeChanged(ivec2(event->size().width(), event->size().height()));
}; };
......
...@@ -31,6 +31,10 @@ namespace TUMVis { ...@@ -31,6 +31,10 @@ namespace TUMVis {
_shader = ShdrMgr.loadSeparate("core/glsl/passthrough.vert", "modules/vis/sliceextractor.frag", "", false); _shader = ShdrMgr.loadSeparate("core/glsl/passthrough.vert", "modules/vis/sliceextractor.frag", "", false);
} }
void SliceExtractor::deinit() {
ShdrMgr.dispose(_shader);
}
void SliceExtractor::process(DataContainer& data) { void SliceExtractor::process(DataContainer& data) {
const ImageDataLocal* img = data.getTypedData<ImageDataLocal>(_sourceImageID.getValue()); const ImageDataLocal* img = data.getTypedData<ImageDataLocal>(_sourceImageID.getValue());
...@@ -40,7 +44,7 @@ namespace TUMVis { ...@@ -40,7 +44,7 @@ namespace TUMVis {
const tgt::svec3& imgSize = img->getSize(); const tgt::svec3& imgSize = img->getSize();
ImageDataLocal* slice = img->getSubImage(tgt::svec3(0, 0, _sliceNumber.getValue()), tgt::svec3(imgSize.x-1, imgSize.y-1, _sliceNumber.getValue())); ImageDataLocal* slice = img->getSubImage(tgt::svec3(0, 0, _sliceNumber.getValue()), tgt::svec3(imgSize.x-1, imgSize.y-1, _sliceNumber.getValue()));
ImageDataGL* glData = ImageDataConverter::tryConvert<ImageDataGL>(slice); ImageDataGL* glData = ImageDataConverter::tryConvert<ImageDataGL>(slice);
ImageDataRenderTarget* rt = new ImageDataRenderTarget(tgt::svec3(_canvasSize.getValue(), 1)); ImageDataRenderTarget* rt = new ImageDataRenderTarget(tgt::svec3(_renderTargetSize.getValue(), 1));
_shader->activate(); _shader->activate();
tgt::TextureUnit inputUnit; tgt::TextureUnit inputUnit;
......
...@@ -26,9 +26,12 @@ namespace TUMVis { ...@@ -26,9 +26,12 @@ namespace TUMVis {
**/ **/
virtual ~SliceExtractor(); virtual ~SliceExtractor();
/// \see AbstractProcessor::init
virtual void init(); virtual void init();
/// \see AbstractProcessor::deinit
virtual void deinit();
virtual void process(DataContainer& data); virtual void process(DataContainer& data);
GenericProperty<std::string> _sourceImageID; ///< image ID for input image GenericProperty<std::string> _sourceImageID; ///< image ID for input image
......