Commit 725f577a authored by schultezub's avatar schultezub

* 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,80 +13,104 @@
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);
}
void TumVisPainter::paint() {
if (getCanvas() == 0)
return;
TumVisPainter::~TumVisPainter() {
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;
void TumVisPainter::stop() {
// we need to execute run() one more time to ensure correct release of the OpenGL context
_stopExecution = true;
_renderCondition.notify_all();
}
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);
Runnable::stop();
}
glActiveTexture(GL_TEXTURE0);
errorTex_->bind();
errorTex_->enable();
void TumVisPainter::run() {
std::unique_lock<tbb::mutex> lock(CtxtMgr.getGlMutex());
glColor3f(1.f, 1.f, 1.f);
renderQuad();
while (! _stopExecution) {
getCanvas()->getContext()->acquire();
paint();
getCanvas()->swap();
errorTex_->disable();*/
while (!_stopExecution && !_dirty)
_renderCondition.wait(lock);
}
LGL_ERROR;
{
tbb::mutex::scoped_lock lock(_localMutex);
_currentlyRendering = false;
// 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);
// 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) {
......@@ -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);
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);
/**
* 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,7 +21,8 @@ namespace TUMVis {
void Runnable::stop() {
_stopExecution = true;
try {
_thread.join();
if (_thread.joinable())
_thread.join();
}
catch(std::exception& e) {
LERRORC("TUMVis.core.tools.Runnable", "Caught exception during _thread.join: " << e.what());
......
......@@ -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"