diff options
author | Tomi Korpipää <tomi.korpipaa@digia.com> | 2014-02-19 14:01:09 +0200 |
---|---|---|
committer | Tomi Korpipää <tomi.korpipaa@digia.com> | 2014-02-20 09:48:19 +0200 |
commit | aa542150122d975a1a6fc097a0ce4e2dd339528e (patch) | |
tree | 5ec1824a5e51d046731d2fefe1dbdf55a5788a91 /src/datavisualizationqml2 | |
parent | e0034b33b9e88aae416d6af0751f5826b9b03924 (diff) |
MSAA support added to QML
Change-Id: I64258705e4423b2762aeff28c3eafd6bdf5d34e9
Reviewed-by: Tomi Korpipää <tomi.korpipaa@digia.com>
Diffstat (limited to 'src/datavisualizationqml2')
-rw-r--r-- | src/datavisualizationqml2/abstractdeclarative.cpp | 143 | ||||
-rw-r--r-- | src/datavisualizationqml2/abstractdeclarative_p.h | 14 | ||||
-rw-r--r-- | src/datavisualizationqml2/declarativerendernode.cpp | 149 | ||||
-rw-r--r-- | src/datavisualizationqml2/declarativerendernode_p.h | 57 |
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 |