2.12.2021, 9:00 - 11:00: Due to updates GitLab may be unavailable for some minutes between 09:00 and 11:00.

Commit 5fbb429e authored by Artur Grunau's avatar Artur Grunau
Browse files

Fix the redrawing of threaded GL canvases

QtThreadedCanvas used to ignore all repaint events send to it by Qt in
order to avoid problems with threading. As a result, however, it would
become blank when docked/undocked, and display garbage in those of its
regions that some other widgets have moved over.

To fix this, the API of TGT's Painter class had to be slightly modified
and now mirrors that of Canvas with regard to painting-related
operations. The paint method has been made protected; it's supposed to
implement the painting logic and shouldn't be called directly. A public
repaint method has been introduced to let canvases notify their
associated painters that they need to be redrawn. The default
implementation simply calls paint() immediately; threaded painters,
however, override it to schedule render jobs that run in separate
threads.

All existing threaded painters have been updated to reduce the
visibility of their paint methods and provide public repaint functions.
Consequently, QtThreadedCanvas can now properly handle repaint events by
delegating to its associated painter's repaint method.
parent cfc3e7ba
......@@ -190,12 +190,16 @@ namespace campvis {
getCanvas()->getEventHandler()->addListenerToFront(_pipeline);
}
void TumVisPainter::onRenderTargetChanged() {
void TumVisPainter::repaint() {
GLJobProc.enqueueJob(getCanvas(), makeJobOnHeap(this, &TumVisPainter::paint), OpenGLJobProcessor::PaintJob);
}
void TumVisPainter::onRenderTargetChanged() {
repaint();
}
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
}
......@@ -79,9 +79,9 @@ namespace campvis {
void run();
/**
* Performs the actual rendering of the pipeline's render target
* Schedule a repaint job for the pipeline's render target
*/
virtual void paint();
virtual void repaint();
/// \see tgt::Painter::sizeChanged
virtual void sizeChanged(const tgt::ivec2& size);
......@@ -114,6 +114,11 @@ namespace campvis {
void onRenderTargetChanged();
private:
/**
* Performs the actual rendering of the pipeline's render target
*/
virtual void paint();
static const std::string loggerCat_;
VisualizationPipeline* _pipeline; ///< Pipeline to render
......
......@@ -210,6 +210,10 @@ namespace campvis {
_quad->createGLBuffers();
}
void DataContainerInspectorCanvas::repaint() {
invalidate();
}
void DataContainerInspectorCanvas::sizeChanged(const tgt::ivec2&) {
invalidate();
}
......@@ -314,4 +318,4 @@ namespace campvis {
invalidate();
}
}
\ No newline at end of file
}
......@@ -94,9 +94,9 @@ namespace campvis {
QSize sizeHint() const;
/**
* Performs the painting.
* Schedule a repaint job for the inspector's render target
*/
void paint();
void repaint();
/// This is meant be overridden to adjust camera settings to new canvas dimensions
virtual void sizeChanged(const tgt::ivec2&);
......@@ -131,6 +131,11 @@ namespace campvis {
void onDataContainerChanged(const QString& key, QtDataHandle dh);
protected:
/**
* Performs the painting.
*/
virtual void paint();
/**
* Gets called when the data collection of this pipeline has changed and thus has notified its observers.
* If \a name equals the name of the renderTarget, the s_renderTargetChanged signal will be emitted.
......
......@@ -224,6 +224,10 @@ namespace campvis {
}
}
void Geometry1DTransferFunctionEditor::repaint() {
invalidate();
}
void Geometry1DTransferFunctionEditor::invalidate() {
GLJobProc.enqueueJob(_canvas, makeJobOnHeap(this, &Geometry1DTransferFunctionEditor::paint), OpenGLJobProcessor::PaintJob);
}
......@@ -348,4 +352,4 @@ namespace campvis {
}
}
\ No newline at end of file
}
......@@ -71,11 +71,10 @@ namespace campvis {
*/
virtual ~Geometry1DTransferFunctionEditor();
/**
* Performs the painting.
* Schedule a repaint job for the editor's render target
*/
void paint();
virtual void repaint();
/// \see tgt::Painter::sizeChanged
virtual void sizeChanged(const tgt::ivec2&);
......@@ -112,6 +111,11 @@ namespace campvis {
void onCbLogScaleStateChanged(int state);
protected:
/**
* Performs the painting.
*/
virtual void paint();
/**
* Gets called when the property has changed, so that widget can update its state.
*/
......
......@@ -210,6 +210,10 @@ namespace campvis {
}
}
void Geometry2DTransferFunctionEditor::repaint() {
invalidate();
}
void Geometry2DTransferFunctionEditor::invalidate() {
GLJobProc.enqueueJob(_canvas, makeJobOnHeap(this, &Geometry2DTransferFunctionEditor::paint), OpenGLJobProcessor::PaintJob);
}
......@@ -299,4 +303,4 @@ namespace campvis {
}
}
\ No newline at end of file
}
......@@ -70,11 +70,10 @@ namespace campvis {
*/
virtual ~Geometry2DTransferFunctionEditor();
/**
* Performs the painting.
* Schedule a repaint job for the editor's render target
*/
void paint();
virtual void repaint();
/// \see tgt::Painter::sizeChanged
virtual void sizeChanged(const tgt::ivec2&);
......@@ -105,6 +104,11 @@ namespace campvis {
void onBtnRemoveGeometryClicked();
protected:
/**
* Performs the painting.
*/
virtual void paint();
/**
* Gets called when the property has changed, so that widget can update its state.
*/
......
......@@ -65,7 +65,7 @@ void GLCanvas::sizeChanged(const ivec2& size) {
void GLCanvas::paint() {
GLContextScopedLock lock(getContext());
if (painter_)
painter_->paint();
painter_->repaint();
if (autoFlush_) {
if (doubleBuffered_) {
swap();
......
......@@ -27,6 +27,10 @@
namespace tgt {
void Painter::repaint() {
paint();
}
Painter::Painter(GLCanvas* canvas)
: canvas_(canvas)
{}
......
......@@ -52,10 +52,15 @@ public:
virtual ~Painter() {}
/**
* This is meant be overridden to do the according openGL paintings
* is not meant to be called directly, will be called by GLCanvas object
* Repaint the associated canvas
*
* This method is not meant to be called directly; it will be called by the associated GLCanvas object when it
* needs to be redrawn.
*
* The default implementation simply calls paint() immediately. Some painters, however, may want to override it to
* schedule render jobs that would run in a separate thread.
*/
virtual void paint() = 0;
virtual void repaint();
/// This is meant be overridden to adjust camera settings to new canvas dimensions
virtual void sizeChanged(const ivec2&) {};
......@@ -73,6 +78,13 @@ public:
/// A wrapper to get the camera from the Canvas
Camera* getCamera() const;
protected:
/**
* This is meant be overridden to do the according openGL paintings
* is not meant to be called directly, will be called by repaint().
*/
virtual void paint() = 0;
private:
GLCanvas* canvas_;
};
......
#include "qtthreadedcanvas.h"
#include "tgt/assert.h"
#include "tgt/painter.h"
namespace tgt {
......@@ -12,16 +13,17 @@ namespace tgt {
}
void QtThreadedCanvas::paintGL() {
// all painting done in threaded painter
}
void QtThreadedCanvas::repaint() {
// all painting done in threaded painter
// skip QtCanvas's repaint implementation and generate a paint event with QWidget's repaint instead
QWidget::repaint();
}
void QtThreadedCanvas::paint() {
// all painting done in threaded painter
}
void QtThreadedCanvas::paintEvent(QPaintEvent* /* event */) {
painter_->repaint();
}
}
......@@ -21,19 +21,7 @@ namespace tgt {
// override Qt events so that they don't interfere with the threading.
void resizeEvent(QResizeEvent *event) {
sizeChanged(ivec2(event->size().width(), event->size().height()));
};
// 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.
*/
virtual void paintGL();
/**
* Called by Qt if there is a paint event; it uses the \a painter_ to paint() something.
*/
virtual void paint();
}
/**
* If you manually want to cause a paint-event, use this function. It will call paintGL()
......@@ -42,6 +30,11 @@ namespace tgt {
virtual void repaint();
protected:
// override Qt events so that they don't interfere with the threading.
virtual void paintEvent(QPaintEvent *event);
// override the paint method so that it doesn't interfere with the threading.
virtual void paint();
};
......
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