summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTomi Korpipää <tomi.korpipaa@digia.com>2014-02-19 14:01:09 +0200
committerTomi Korpipää <tomi.korpipaa@digia.com>2014-02-20 09:48:19 +0200
commitaa542150122d975a1a6fc097a0ce4e2dd339528e (patch)
tree5ec1824a5e51d046731d2fefe1dbdf55a5788a91 /src
parente0034b33b9e88aae416d6af0751f5826b9b03924 (diff)
MSAA support added to QML
Change-Id: I64258705e4423b2762aeff28c3eafd6bdf5d34e9 Reviewed-by: Tomi Korpipää <tomi.korpipaa@digia.com>
Diffstat (limited to 'src')
-rw-r--r--src/datavisualizationqml2/abstractdeclarative.cpp143
-rw-r--r--src/datavisualizationqml2/abstractdeclarative_p.h14
-rw-r--r--src/datavisualizationqml2/declarativerendernode.cpp149
-rw-r--r--src/datavisualizationqml2/declarativerendernode_p.h57
4 files changed, 269 insertions, 94 deletions
diff --git a/src/datavisualizationqml2/abstractdeclarative.cpp b/src/datavisualizationqml2/abstractdeclarative.cpp
index 97929302..88a86925 100644
--- a/src/datavisualizationqml2/abstractdeclarative.cpp
+++ b/src/datavisualizationqml2/abstractdeclarative.cpp
@@ -22,8 +22,6 @@
#include "declarativerendernode_p.h"
#include <QtCore/QThread>
-#include <QtGui/QGuiApplication>
-#include <QtQuick/QSGSimpleRectNode>
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -34,7 +32,15 @@ static QHash<QQuickWindow *, bool> windowClearList;
AbstractDeclarative::AbstractDeclarative(QQuickItem *parent) :
QQuickItem(parent),
m_controller(0),
- m_renderMode(RenderDirectToBackground),
+ m_context(0),
+ m_qtContext(0),
+ m_contextWindow(0),
+ m_renderMode(RenderIndirect),
+#if defined(QT_OPENGL_ES_2)
+ m_samples(0),
+#else
+ m_samples(4),
+#endif
m_initialisedSize(0, 0)
{
connect(this, &QQuickItem::windowChanged, this, &AbstractDeclarative::handleWindowChanged);
@@ -43,10 +49,17 @@ AbstractDeclarative::AbstractDeclarative(QQuickItem *parent) :
#else
setAntialiasing(false);
#endif
+ setFlag(ItemHasContents, true);
}
AbstractDeclarative::~AbstractDeclarative()
{
+ // Context can be in another thread, don't delete it directly in that case
+ if (m_context && m_context->thread() != QThread::currentThread())
+ m_context->deleteLater();
+ else
+ delete m_context;
+
disconnect(this, 0, this, 0);
checkWindowList(0);
}
@@ -68,22 +81,34 @@ void AbstractDeclarative::setRenderingMode(AbstractDeclarative::RenderingMode mo
case RenderDirectToBackground_NoClear:
m_initialisedSize = QSize(0, 0);
#if !defined(QT_OPENGL_ES_2)
- setAntialiasing(true);
+ if (win && win->format().samples() > 0)
+ setAntialiasing(true);
+ else
+ setAntialiasing(false);
#else
setAntialiasing(false);
#endif
setFlag(ItemHasContents, false);
- if (win && previousMode == RenderIndirect_NoAA) {
+ if (win && previousMode == RenderIndirect) {
QObject::connect(win, &QQuickWindow::beforeRendering, this,
&AbstractDeclarative::render);
checkWindowList(win);
+ int samples = win->format().samples();
+ if (samples != m_samples)
+ emit msaaSamplesChanged(samples);
}
break;
- case RenderIndirect_NoAA:
- // Force recreation of render node by resetting the initialized size
+ case RenderIndirect:
+#if !defined(QT_OPENGL_ES_2)
+ if (m_samples > 0)
+ setAntialiasing(true);
+ else
+ setAntialiasing(false);
+#else
setAntialiasing(false);
+#endif
m_initialisedSize = QSize(0, 0);
setFlag(ItemHasContents, true);
if (win) {
@@ -106,25 +131,25 @@ AbstractDeclarative::RenderingMode AbstractDeclarative::renderingMode() const
QSGNode *AbstractDeclarative::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
- // If old node exists and has right size, reuse it.
- if (oldNode && m_initialisedSize == boundingRect().size().toSize()) {
- // Update bounding rectangle (that has same size as before).
- DeclarativeRenderNode *renderNode = static_cast<DeclarativeRenderNode *>(oldNode);
- renderNode->setRect(boundingRect());
- return oldNode;
+ QSize boundingSize = boundingRect().size().toSize();
+ if (boundingSize.width() <= 0 || boundingSize.height() <= 0
+ || m_controller.isNull() || !window()) {
+ delete oldNode;
+ return 0;
}
+ DeclarativeRenderNode *node = static_cast<DeclarativeRenderNode *>(oldNode);
- // Create a new render node when size changes or if there is no node yet
- m_initialisedSize = boundingRect().size().toSize();
+ if (!node) {
+ node = new DeclarativeRenderNode(this);
+ node->setController(m_controller.data());
+ node->setQuickWindow(window());
+ }
- // Delete old node
- if (oldNode)
- delete oldNode;
+ node->setSize(boundingSize);
+ node->setSamples(m_samples);
+ node->update();
+ node->markDirty(QSGNode::DirtyMaterial);
- // Create a new one and set its bounding rectangle
- DeclarativeRenderNode *node = new DeclarativeRenderNode(window(), m_controller,
- m_renderMode, this);
- node->setRect(boundingRect());
return node;
}
@@ -198,12 +223,65 @@ void AbstractDeclarative::setSharedController(Abstract3DController *controller)
&AbstractDeclarative::handleAxisZChanged);
}
+void AbstractDeclarative::activateOpenGLContext(QQuickWindow *window)
+{
+ if (!m_context || m_contextWindow != window) {
+ m_contextWindow = window;
+ delete m_context;
+ m_qtContext = QOpenGLContext::currentContext();
+ m_context = new QOpenGLContext();
+ m_context->setFormat(window->requestedFormat());
+ m_context->setShareContext(m_qtContext);
+ m_context->create();
+ }
+ m_context->makeCurrent(window);
+}
+
+void AbstractDeclarative::doneOpenGLContext(QQuickWindow *window)
+{
+ m_qtContext->makeCurrent(window);
+}
+
void AbstractDeclarative::synchDataToRenderer()
{
if (m_renderMode == RenderDirectToBackground && clearList.size())
clearList.clear();
+
+ QQuickWindow *win = window();
+ activateOpenGLContext(win);
m_controller->initializeOpenGL();
m_controller->synchDataToRenderer();
+ doneOpenGLContext(win);
+}
+
+int AbstractDeclarative::msaaSamples() const
+{
+ int samples = m_samples;
+ if (window() && m_renderMode != RenderIndirect)
+ samples = window()->format().samples();
+ return samples;
+}
+
+void AbstractDeclarative::setMsaaSamples(int samples)
+{
+ if (m_renderMode != RenderIndirect) {
+ qWarning("Multisampling cannot be adjusted in this render mode");
+ } else {
+#if defined(QT_OPENGL_ES_2)
+ if (samples > 0)
+ qWarning("Multisampling is not supported in OpenGL ES2");
+#else
+ if (m_samples != samples) {
+ m_samples = samples;
+ if (m_samples > 0)
+ setAntialiasing(true);
+ else
+ setAntialiasing(false);
+ emit msaaSamplesChanged(samples);
+ update();
+ }
+#endif
+ }
}
void AbstractDeclarative::handleWindowChanged(QQuickWindow *window)
@@ -216,13 +294,17 @@ void AbstractDeclarative::handleWindowChanged(QQuickWindow *window)
connect(window, &QQuickWindow::beforeSynchronizing,
this, &AbstractDeclarative::synchDataToRenderer,
Qt::DirectConnection);
- if (m_renderMode == RenderDirectToBackground_NoClear || m_renderMode == RenderDirectToBackground) {
- connect(window, &QQuickWindow::beforeRendering,
- this, &AbstractDeclarative::render,
+
+ if (m_renderMode == RenderDirectToBackground_NoClear
+ || m_renderMode == RenderDirectToBackground) {
+ connect(window, &QQuickWindow::beforeRendering, this, &AbstractDeclarative::render,
Qt::DirectConnection);
+ QQuickWindow *oldWindow = graphWindowList.value(this);
+ int samples = window->format().samples();
+ if (oldWindow && samples != oldWindow->format().samples())
+ emit msaaSamplesChanged(samples);
}
- connect(m_controller.data(), &Abstract3DController::needRender,
- window, &QQuickWindow::update);
+ connect(m_controller.data(), &Abstract3DController::needRender, window, &QQuickWindow::update);
updateWindowParameters();
}
@@ -301,7 +383,8 @@ void AbstractDeclarative::render()
return;
// Clear the background once per window as that is not done by default
- const QQuickWindow *win = window();
+ QQuickWindow *win = window();
+ activateOpenGLContext(win);
if (m_renderMode == RenderDirectToBackground && !clearList.contains(win)) {
clearList.append(win);
QColor clearColor = win->color();
@@ -321,6 +404,7 @@ void AbstractDeclarative::render()
glEnable(GL_BLEND);
}
+ doneOpenGLContext(win);
}
QAbstract3DInputHandler* AbstractDeclarative::inputHandler() const
@@ -405,7 +489,8 @@ void AbstractDeclarative::checkWindowList(QQuickWindow *window)
return;
}
- if ((m_renderMode == RenderDirectToBackground || m_renderMode == RenderDirectToBackground_NoClear)
+ if ((m_renderMode == RenderDirectToBackground
+ || m_renderMode == RenderDirectToBackground_NoClear)
&& windowClearList.values(window).size() == 0) {
// Save old clear value
windowClearList[window] = window->clearBeforeRendering();
diff --git a/src/datavisualizationqml2/abstractdeclarative_p.h b/src/datavisualizationqml2/abstractdeclarative_p.h
index e5e9909b..8be3e0fa 100644
--- a/src/datavisualizationqml2/abstractdeclarative_p.h
+++ b/src/datavisualizationqml2/abstractdeclarative_p.h
@@ -51,6 +51,7 @@ class AbstractDeclarative : public QQuickItem
Q_FLAGS(SelectionFlag SelectionFlags)
Q_PROPERTY(SelectionFlags selectionMode READ selectionMode WRITE setSelectionMode NOTIFY selectionModeChanged)
Q_PROPERTY(ShadowQuality shadowQuality READ shadowQuality WRITE setShadowQuality NOTIFY shadowQualityChanged)
+ Q_PROPERTY(int msaaSamples READ msaaSamples WRITE setMsaaSamples NOTIFY msaaSamplesChanged)
Q_PROPERTY(Declarative3DScene* scene READ scene NOTIFY sceneChanged)
Q_PROPERTY(QAbstract3DInputHandler* inputHandler READ inputHandler WRITE setInputHandler NOTIFY inputHandlerChanged)
Q_PROPERTY(Q3DTheme* theme READ theme WRITE setTheme NOTIFY themeChanged)
@@ -84,7 +85,7 @@ public:
enum RenderingMode {
RenderDirectToBackground = 0,
RenderDirectToBackground_NoClear,
- RenderIndirect_NoAA
+ RenderIndirect
};
public:
@@ -100,6 +101,9 @@ public:
virtual void setShadowQuality(ShadowQuality quality);
virtual AbstractDeclarative::ShadowQuality shadowQuality() const;
+ virtual void setMsaaSamples(int samples);
+ virtual int msaaSamples() const;
+
virtual Declarative3DScene *scene() const;
virtual QAbstract3DInputHandler *inputHandler() const;
@@ -117,6 +121,9 @@ public:
void synchDataToRenderer();
void render();
+ void activateOpenGLContext(QQuickWindow *window);
+ void doneOpenGLContext(QQuickWindow *window);
+
void checkWindowList(QQuickWindow *window);
public slots:
@@ -141,6 +148,7 @@ protected:
signals:
void selectionModeChanged(SelectionFlags mode);
void shadowQualityChanged(ShadowQuality quality);
+ void msaaSamplesChanged(int samples);
void sceneChanged(Q3DScene *scene);
void inputHandlerChanged(QAbstract3DInputHandler *inputHandler);
void themeChanged(Q3DTheme *theme);
@@ -149,7 +157,11 @@ signals:
private:
QPointer<Abstract3DController> m_controller;
QRectF m_cachedGeometry;
+ QOpenGLContext *m_context;
+ QOpenGLContext *m_qtContext;
+ QQuickWindow *m_contextWindow;
AbstractDeclarative::RenderingMode m_renderMode;
+ int m_samples;
QSize m_initialisedSize;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractDeclarative::SelectionFlags)
diff --git a/src/datavisualizationqml2/declarativerendernode.cpp b/src/datavisualizationqml2/declarativerendernode.cpp
index f4ce7532..b22d2633 100644
--- a/src/datavisualizationqml2/declarativerendernode.cpp
+++ b/src/datavisualizationqml2/declarativerendernode.cpp
@@ -17,72 +17,131 @@
****************************************************************************/
#include "declarativerendernode_p.h"
-#include <QtQuick/QQuickWindow>
+#include "abstract3dcontroller_p.h"
+#include "abstractdeclarative_p.h"
+#include <QtGui/QOpenGLContext>
#include <QtGui/QOpenGLFramebufferObject>
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
-DeclarativeRenderNode::DeclarativeRenderNode(QQuickWindow *window,
- Abstract3DController *controller,
- AbstractDeclarative::RenderingMode mode,
- QObject *parent)
- : QObject(parent),
- m_fbo(0),
- m_texture(0),
- m_window(window),
- m_controller(controller),
- m_mode(mode)
+DeclarativeRenderNode::DeclarativeRenderNode(AbstractDeclarative *declarative)
+ : QSGGeometryNode(),
+ m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4),
+ m_texture(0),
+ m_declarative(declarative),
+ m_controller(0),
+ m_fbo(0),
+ m_multisampledFBO(0),
+ m_window(0),
+ m_dirtyFBO(false),
+ m_samples(0)
{
- connect(window, &QQuickWindow::beforeRendering,
- this, &DeclarativeRenderNode::renderFBO,
- Qt::DirectConnection);
+ setMaterial(&m_material);
+ setOpaqueMaterial(&m_materialO);
+ setGeometry(&m_geometry);
+ setFlag(UsePreprocess);
}
DeclarativeRenderNode::~DeclarativeRenderNode()
{
- delete m_texture;
delete m_fbo;
+ delete m_multisampledFBO;
}
-void DeclarativeRenderNode::renderFBO()
+void DeclarativeRenderNode::setSize(const QSize &size)
{
- QSize size = rect().size().toSize();
-
- if (size.width() <= 0 || size.height() <= 0)
+ if (size == m_size)
return;
- // Create FBO
- if (!m_fbo) {
- QOpenGLFramebufferObjectFormat format;
- format.setAttachment(QOpenGLFramebufferObject::Depth);
- m_fbo = new QOpenGLFramebufferObject(size, format);
- m_texture = m_window->createTextureFromId(m_fbo->texture(), size);
-
- setTexture(m_texture);
-
- // Flip texture
- QSize ts = m_texture->textureSize();
- QRectF sourceRect(0, 0, ts.width(), ts.height());
- float tmp = sourceRect.top();
- sourceRect.setTop(sourceRect.bottom());
- sourceRect.setBottom(tmp);
- QSGGeometry *geometry = this->geometry();
- QSGGeometry::updateTexturedRectGeometry(geometry, rect(),
- m_texture->convertToNormalizedSourceRect(sourceRect));
- markDirty(DirtyMaterial);
+ m_size = size;
+ m_dirtyFBO = true;
+ markDirty(DirtyGeometry);
+}
+
+void DeclarativeRenderNode::update()
+{
+ if (m_dirtyFBO) {
+ updateFBO();
+ m_dirtyFBO = false;
}
+}
+
+void DeclarativeRenderNode::updateFBO()
+{
+ m_declarative->activateOpenGLContext(m_window);
+
+ if (m_fbo)
+ delete m_fbo;
+
+ m_fbo = new QOpenGLFramebufferObject(m_size);
+ m_fbo->setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
+
+ // Multisampled
+ if (m_multisampledFBO) {
+ delete m_multisampledFBO;
+ m_multisampledFBO = 0;
+ }
+ if (m_samples > 0) {
+ QOpenGLFramebufferObjectFormat multisampledFrambufferFormat;
+ multisampledFrambufferFormat.setSamples(m_samples);
+ multisampledFrambufferFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
+
+ m_multisampledFBO = new QOpenGLFramebufferObject(m_size, multisampledFrambufferFormat);
+ }
+
+ QSGGeometry::updateTexturedRectGeometry(&m_geometry,
+ QRectF(0, 0, m_size.width(), m_size.height()),
+ QRectF(0, 1, 1, -1));
+
+ delete m_texture;
+ m_texture = m_window->createTextureFromId(m_fbo->texture(), m_size);
+ m_material.setTexture(m_texture);
+ m_materialO.setTexture(m_texture);
+
+ m_declarative->doneOpenGLContext(m_window);
+}
+
+void DeclarativeRenderNode::setQuickWindow(QQuickWindow *window)
+{
+ Q_ASSERT(window);
+
+ m_window = window;
+}
+
+void DeclarativeRenderNode::setController(Abstract3DController *controller)
+{
+ m_controller = controller;
+}
+
+void DeclarativeRenderNode::setSamples(int samples)
+{
+ if (m_samples == samples)
+ return;
+
+ m_samples = samples;
+ m_dirtyFBO = true;
+}
+
+void DeclarativeRenderNode::preprocess()
+{
+ QOpenGLFramebufferObject *targetFBO;
+ if (m_samples > 0)
+ targetFBO = m_multisampledFBO;
+ else
+ targetFBO = m_fbo;
- // Call the shared rendering function
- m_fbo->bind();
- glDisable(GL_BLEND);
+ m_declarative->activateOpenGLContext(m_window);
- m_controller->render(m_fbo->handle());
+ targetFBO->bind();
+ // Render scene here
+ m_controller->render(targetFBO->handle());
- glEnable(GL_BLEND);
+ targetFBO->release();
- m_fbo->release();
+ if (m_samples > 0)
+ QOpenGLFramebufferObject::blitFramebuffer(m_fbo, m_multisampledFBO);
- // New view is in the FBO, request repaint of scene graph
+ m_declarative->doneOpenGLContext(m_window);
}
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualizationqml2/declarativerendernode_p.h b/src/datavisualizationqml2/declarativerendernode_p.h
index 559e27e1..aa058eee 100644
--- a/src/datavisualizationqml2/declarativerendernode_p.h
+++ b/src/datavisualizationqml2/declarativerendernode_p.h
@@ -20,44 +20,63 @@
// W A R N I N G
// -------------
//
-// This file is not part of the QtDataVis3D API. It exists purely as an
+// This file is not part of the QtDataVisualization API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
-#ifndef DECLARATIVERENDERNODE_P_H
-#define DECLARATIVERENDERNODE_P_H
+#ifndef DeclarativeRenderNode_P_H
+#define DeclarativeRenderNode_P_H
-#include <QObject>
#include "datavisualizationglobal_p.h"
-#include "abstract3dcontroller_p.h"
-#include "abstractdeclarative_p.h"
-#include <qsgsimpletexturenode.h>
+#include <QtQuick/QSGGeometryNode>
+#include <QtQuick/QSGTextureMaterial>
+#include <QtQuick/QSGOpaqueTextureMaterial>
+#include <QtQuick/QQuickWindow>
+
+class QOpenGLContext;
class QOpenGLFramebufferObject;
-class QSGTexture;
-class QQuickWindow;
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
-class DeclarativeRenderNode : public QObject, public QSGSimpleTextureNode
+class Abstract3DController;
+class AbstractDeclarative;
+
+class DeclarativeRenderNode : public QSGGeometryNode
{
- Q_OBJECT
public:
- explicit DeclarativeRenderNode(QQuickWindow *window, Abstract3DController *controller,
- AbstractDeclarative::RenderingMode mode, QObject *parent = 0);
- virtual ~DeclarativeRenderNode();
+ DeclarativeRenderNode(AbstractDeclarative *declarative);
+ ~DeclarativeRenderNode();
+
+ void setSize(const QSize &size);
+ QSize size() const { return m_size; }
+
+ void update();
+ void updateFBO();
+
+ void setController(Abstract3DController *controller);
+ void setQuickWindow(QQuickWindow *window);
+ void setSamples(int samples);
- // Renders view to FBO before render cycle starts.
- void renderFBO();
+ void preprocess();
private:
- QOpenGLFramebufferObject *m_fbo;
+ QSGTextureMaterial m_material;
+ QSGOpaqueTextureMaterial m_materialO;
+ QSGGeometry m_geometry;
QSGTexture *m_texture;
+ QSize m_size;
+
+ AbstractDeclarative *m_declarative;
+ Abstract3DController *m_controller;
+ QOpenGLFramebufferObject *m_fbo;
+ QOpenGLFramebufferObject *m_multisampledFBO;
QQuickWindow *m_window;
- QPointer<Abstract3DController> m_controller;
- AbstractDeclarative::RenderingMode m_mode;
+ int m_samples;
+
+ bool m_dirtyFBO;
};
QT_END_NAMESPACE_DATAVISUALIZATION