From 4cb2552313280384b59ee1e7d7fc557c7bd64a68 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 15 Jul 2016 13:43:08 +0200 Subject: software: Add support for QSGRenderNode Have to change getResource() a bit since it turns out it is not suitable currently for backends that do not have a per-window rendercontext and do not implement the interface on the rendercontext. Pass in the window to make sure it can always figure out which window we want the resources for. (we do not want rendererInterface() to return window-specific instances created on the fly, with ownership issues, so stick with the simple model where backends implement the interface on one of their existing classes) To support clipping, QSGRenderNode::RenderState is extended accordingly. Also updated the docs since some claims in the rendernode docs are not true since Qt 5.3. Change-Id: I34779c83926f5231b888fcab7131e873ae97964f Reviewed-by: Andy Nichols --- .../adaptations/software/qsgsoftwarecontext.cpp | 11 +++++ .../adaptations/software/qsgsoftwarecontext_p.h | 2 + .../software/qsgsoftwarepixmaprenderer.cpp | 5 ++ .../software/qsgsoftwarerenderablenode.cpp | 53 +++++++++++++++++++--- .../software/qsgsoftwarerenderablenode_p.h | 5 +- .../software/qsgsoftwarerenderablenodeupdater.cpp | 19 +++++++- .../software/qsgsoftwarerenderablenodeupdater_p.h | 2 + .../adaptations/software/qsgsoftwarerenderer.cpp | 4 ++ .../software/qsgsoftwarerenderlistbuilder.cpp | 12 ++++- .../software/qsgsoftwarerenderlistbuilder_p.h | 2 + src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp | 1 + .../scenegraph/coreapi/qsgrendererinterface.cpp | 17 +++++-- .../scenegraph/coreapi/qsgrendererinterface.h | 9 ++-- src/quick/scenegraph/coreapi/qsgrendernode.cpp | 34 +++++++++----- src/quick/scenegraph/coreapi/qsgrendernode.h | 1 + src/quick/scenegraph/qsgadaptationlayer.cpp | 8 ++++ src/quick/scenegraph/qsgadaptationlayer_p.h | 3 ++ 17 files changed, 160 insertions(+), 28 deletions(-) (limited to 'src/quick/scenegraph') diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp index 94e9c81f70..80112c1121 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp @@ -53,6 +53,7 @@ #include #include +#include // Used for very high-level info about the renderering and gl context // Includes GL_VERSION, type of render loop, atlas size, etc. @@ -82,8 +83,10 @@ QT_BEGIN_NAMESPACE QSGSoftwareRenderContext::QSGSoftwareRenderContext(QSGContext *ctx) : QSGRenderContext(ctx) , m_initialized(false) + , m_activePainter(nullptr) { } + QSGSoftwareContext::QSGSoftwareContext(QObject *parent) : QSGContext(parent) { @@ -206,4 +209,12 @@ QSGRendererInterface::ShaderSourceTypes QSGSoftwareContext::shaderSourceType() c return 0; } +void *QSGSoftwareContext::getResource(QQuickWindow *window, Resource resource) const +{ + if (resource == Painter && window && window->isSceneGraphInitialized()) + return static_cast(QQuickWindowPrivate::get(window)->context)->m_activePainter; + + return nullptr; +} + QT_END_NAMESPACE diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h index 3c3686c268..dcc137b4b4 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h @@ -78,6 +78,7 @@ public: int maxTextureSize() const override; bool m_initialized; + QPainter *m_activePainter; }; class QSGSoftwareContext : public QSGContext, public QSGRendererInterface @@ -103,6 +104,7 @@ public: ShaderType shaderType() const override; ShaderCompilationTypes shaderCompilationType() const override; ShaderSourceTypes shaderSourceType() const override; + void *getResource(QQuickWindow *window, Resource resource) const override; }; QT_END_NAMESPACE diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp index 304106a84d..f8c1a3d90b 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "qsgsoftwarepixmaprenderer_p.h" +#include "qsgsoftwarecontext_p.h" #include @@ -84,6 +85,9 @@ void QSGSoftwarePixmapRenderer::render(QPaintDevice *target) QPainter painter(target); painter.setRenderHint(QPainter::Antialiasing); painter.setWindow(m_projectionRect); + auto rc = static_cast(context()); + QPainter *prevPainter = rc->m_activePainter; + rc->m_activePainter = &painter; renderTimer.start(); buildRenderList(); @@ -100,6 +104,7 @@ void QSGSoftwarePixmapRenderer::render(QPaintDevice *target) QRegion paintedRegion = renderNodes(&painter); qint64 renderTime = renderTimer.elapsed(); + rc->m_activePainter = prevPainter; qCDebug(lcPixmapRenderer) << "pixmapRender" << paintedRegion << buildRenderListTime << optimizeRenderListTime << renderTime; } diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp index 1b2a836dfa..032a06f946 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp @@ -47,8 +47,9 @@ #include "qsgsoftwarepixmaptexture_p.h" #include "qsgsoftwarespritenode_p.h" -#include -#include +#include +#include +#include #include Q_LOGGING_CATEGORY(lcRenderable, "qt.scenegraph.softwarecontext.renderable") @@ -93,6 +94,9 @@ QSGSoftwareRenderableNode::QSGSoftwareRenderableNode(NodeType type, QSGNode *nod case QSGSoftwareRenderableNode::SpriteNode: m_handle.spriteNode = static_cast(node); break; + case QSGSoftwareRenderableNode::RenderNode: + m_handle.renderNode = static_cast(node); + break; case QSGSoftwareRenderableNode::Invalid: m_handle.simpleRectNode = nullptr; break; @@ -182,6 +186,8 @@ void QSGSoftwareRenderableNode::update() m_isOpaque = m_handle.spriteNode->isOpaque(); boundingRect = m_handle.spriteNode->rect().toRect(); break; + case QSGSoftwareRenderableNode::RenderNode: + break; default: break; } @@ -203,15 +209,50 @@ void QSGSoftwareRenderableNode::update() m_dirtyRegion = QRegion(m_boundingRect); } +struct RenderNodeState : public QSGRenderNode::RenderState +{ + const QMatrix4x4 *projectionMatrix() const override { return &ident; } + QRect scissorRect() const { return QRect(); } + bool scissorEnabled() const { return false; } + int stencilValue() const { return 0; } + bool stencilEnabled() const { return false; } + const QRegion *clipRegion() const { return &cr; } + QMatrix4x4 ident; + QRegion cr; +}; + QRegion QSGSoftwareRenderableNode::renderNode(QPainter *painter, bool forceOpaquePainting) { Q_ASSERT(painter); // Check for don't paint conditions - if (!m_isDirty || qFuzzyIsNull(m_opacity) || m_dirtyRegion.isEmpty()) { - m_isDirty = false; - m_dirtyRegion = QRegion(); - return QRegion(); + if (m_nodeType != RenderNode) { + if (!m_isDirty || qFuzzyIsNull(m_opacity) || m_dirtyRegion.isEmpty()) { + m_isDirty = false; + m_dirtyRegion = QRegion(); + return QRegion(); + } + } else { + if (!m_isDirty || qFuzzyIsNull(m_opacity)) { + m_isDirty = false; + m_dirtyRegion = QRegion(); + return QRegion(); + } else { + QSGRenderNodePrivate *rd = QSGRenderNodePrivate::get(m_handle.renderNode); + QMatrix4x4 m = m_transform; + rd->m_matrix = &m; + rd->m_opacity = m_opacity; + RenderNodeState rs; + rs.cr = m_clipRegion; + painter->save(); + m_handle.renderNode->render(&rs); + painter->restore(); + const QRect fullRect = QRect(0, 0, painter->device()->width(), painter->device()->height()); + m_previousDirtyRegion = fullRect; + m_isDirty = false; + m_dirtyRegion = QRegion(); + return fullRect; + } } painter->save(); diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h index dc224be2c0..0626b1e657 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h @@ -68,6 +68,7 @@ class QSGSoftwareInternalRectangleNode; class QSGSoftwareGlyphNode; class QSGSoftwareNinePatchNode; class QSGSoftwareSpriteNode; +class QSGRenderNode; class QSGSoftwareRenderableNode { @@ -83,7 +84,8 @@ public: NinePatch, SimpleRectangle, SimpleImage, - SpriteNode + SpriteNode, + RenderNode }; QSGSoftwareRenderableNode(NodeType type, QSGNode *node); @@ -126,6 +128,7 @@ private: QSGRectangleNode *simpleRectangleNode; QSGImageNode *simpleImageNode; QSGSoftwareSpriteNode *spriteNode; + QSGRenderNode *renderNode; }; const NodeType m_nodeType; diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp index cb866bec12..82f8623b74 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp @@ -47,8 +47,9 @@ #include "qsgsoftwarepainternode_p.h" #include "qsgsoftwarepixmaptexture_p.h" -#include +#include #include +#include QT_BEGIN_NAMESPACE @@ -190,6 +191,15 @@ void QSGSoftwareRenderableNodeUpdater::endVisit(QSGSpriteNode *) } +bool QSGSoftwareRenderableNodeUpdater::visit(QSGRenderNode *node) +{ + return updateRenderableNode(QSGSoftwareRenderableNode::RenderNode, node); +} + +void QSGSoftwareRenderableNodeUpdater::endVisit(QSGRenderNode *) +{ +} + void QSGSoftwareRenderableNodeUpdater::updateNodes(QSGNode *node, bool isNodeRemoved) { m_opacityState.clear(); @@ -269,6 +279,13 @@ void QSGSoftwareRenderableNodeUpdater::updateNodes(QSGNode *node, bool isNodeRem visitChildren(node); break; } + case QSGNode::RenderNodeType: { + QSGRenderNode *r = static_cast(node); + if (visit(r)) + visitChildren(r); + endVisit(r); + break; + } default: Q_UNREACHABLE(); break; diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater_p.h index 5bc241cce1..f204867236 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater_p.h @@ -88,6 +88,8 @@ public: void endVisit(QSGRootNode *) override; bool visit(QSGSpriteNode *) override; void endVisit(QSGSpriteNode *) override; + bool visit(QSGRenderNode *) override; + void endVisit(QSGRenderNode *) override; void updateNodes(QSGNode *node, bool isNodeRemoved = false); diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp index 257009472e..ae89ed7d8a 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp @@ -138,6 +138,9 @@ void QSGSoftwareRenderer::render() QPainter painter(m_paintDevice); painter.setRenderHint(QPainter::Antialiasing); + auto rc = static_cast(context()); + QPainter *prevPainter = rc->m_activePainter; + rc->m_activePainter = &painter; // Render the contents Renderlist m_flushRegion = renderNodes(&painter); @@ -146,6 +149,7 @@ void QSGSoftwareRenderer::render() if (m_backingStore != nullptr) m_backingStore->endPaint(); + rc->m_activePainter = prevPainter; qCDebug(lcRenderer) << "render" << m_flushRegion << buildRenderListTime << optimizeRenderListTime << renderTime; } diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder.cpp index ac00127b35..4e34517dad 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder.cpp @@ -48,8 +48,9 @@ #include "qsgsoftwarepainternode_p.h" #include "qsgsoftwarepixmaptexture_p.h" -#include +#include #include +#include QT_BEGIN_NAMESPACE @@ -150,6 +151,15 @@ void QSGSoftwareRenderListBuilder::endVisit(QSGSpriteNode *) } +bool QSGSoftwareRenderListBuilder::visit(QSGRenderNode *node) +{ + return addRenderableNode(node); +} + +void QSGSoftwareRenderListBuilder::endVisit(QSGRenderNode *) +{ +} + bool QSGSoftwareRenderListBuilder::addRenderableNode(QSGNode *node) { auto renderableNode = m_renderer->renderableNode(node); diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder_p.h index e34cc81e23..807cb7fdbe 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder_p.h @@ -82,6 +82,8 @@ public: void endVisit(QSGRootNode *) override; bool visit(QSGSpriteNode *) override; void endVisit(QSGSpriteNode *) override; + bool visit(QSGRenderNode *) override; + void endVisit(QSGRenderNode *) override; private: bool addRenderableNode(QSGNode *node); diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index d45a0ea75d..bee2015007 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -2768,6 +2768,7 @@ struct RenderNodeState : public QSGRenderNode::RenderState bool scissorEnabled() const override { return m_scissorEnabled; } int stencilValue() const override { return m_stencilValue; } bool stencilEnabled() const override { return m_stencilEnabled; } + const QRegion *clipRegion() const override { return nullptr; } const QMatrix4x4 *m_projectionMatrix; QRect m_scissorRect; diff --git a/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp b/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp index 04e71441f6..fa543aecad 100644 --- a/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp +++ b/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp @@ -81,9 +81,10 @@ QT_BEGIN_NAMESPACE /*! \enum QSGRendererInterface::Resource - \value Device The graphics device - \value CommandQueue The graphics command queue used by the scenergaph - \value CommandList The command list or buffer used by the scenegraph + \value Device The graphics device, when applicable. + \value CommandQueue The graphics command queue used by the scenegraph, when applicable. + \value CommandList The command list or buffer used by the scenegraph, when applicable. + \value Painter The active QPainter used by the scenegraph, when running with the software backend. */ /*! @@ -134,10 +135,13 @@ QSGRendererInterface::~QSGRendererInterface() example, \c{VkDevice dev = *static_cast(result)}). The latter is necessary since such handles may have sizes different from a pointer. + \note The ownership of the returned pointer is never transferred to the caller. + \note This function must only be called on the render thread. */ -void *QSGRendererInterface::getResource(Resource resource) const +void *QSGRendererInterface::getResource(QQuickWindow *window, Resource resource) const { + Q_UNUSED(window); Q_UNUSED(resource); return nullptr; } @@ -147,10 +151,13 @@ void *QSGRendererInterface::getResource(Resource resource) const allows supporting any future resources that are not listed in the Resource enum. + \note The ownership of the returned pointer is never transferred to the caller. + \note This function must only be called on the render thread. */ -void *QSGRendererInterface::getResource(const char *resource) const +void *QSGRendererInterface::getResource(QQuickWindow *window, const char *resource) const { + Q_UNUSED(window); Q_UNUSED(resource); return nullptr; } diff --git a/src/quick/scenegraph/coreapi/qsgrendererinterface.h b/src/quick/scenegraph/coreapi/qsgrendererinterface.h index 234a061d0e..a50b362aeb 100644 --- a/src/quick/scenegraph/coreapi/qsgrendererinterface.h +++ b/src/quick/scenegraph/coreapi/qsgrendererinterface.h @@ -44,6 +44,8 @@ QT_BEGIN_NAMESPACE +class QQuickWindow; + class Q_QUICK_EXPORT QSGRendererInterface { public: @@ -57,7 +59,8 @@ public: enum Resource { Device, CommandQueue, - CommandList + CommandList, + Painter }; enum ShaderType { @@ -83,8 +86,8 @@ public: virtual GraphicsApi graphicsApi() const = 0; - virtual void *getResource(Resource resource) const; - virtual void *getResource(const char *resource) const; + virtual void *getResource(QQuickWindow *window, Resource resource) const; + virtual void *getResource(QQuickWindow *window, const char *resource) const; virtual ShaderType shaderType() const = 0; virtual ShaderCompilationTypes shaderCompilationType() const = 0; diff --git a/src/quick/scenegraph/coreapi/qsgrendernode.cpp b/src/quick/scenegraph/coreapi/qsgrendernode.cpp index 29e8251cb2..365abd09e2 100644 --- a/src/quick/scenegraph/coreapi/qsgrendernode.cpp +++ b/src/quick/scenegraph/coreapi/qsgrendernode.cpp @@ -111,6 +111,10 @@ QSGRenderNodePrivate::QSGRenderNodePrivate() call related settings (root signature, descriptor heaps, etc.) are always set again by the scenegraph so render() can freely change them. + The software backend exposes its QPainter and saves and restores before and + after invoking render(). Therefore reporting any changed states from here + is not necessary. + \note This function may be called before render(). */ QSGRenderNode::StateFlags QSGRenderNode::changedStates() const @@ -125,17 +129,6 @@ QSGRenderNode::StateFlags QSGRenderNode::changedStates() const directly invoking commands in the graphics API (OpenGL, Direct3D, etc.) currently in use. - The states necessary for clipping has already been set before the function - is called. The clip is a combination of a stencil clip and scissor clip. - Information about the clip is found in \a state. - - \note This means that setting viewport, scissor rectangle, stencil - reference value, and similar is not necessary in render() since the - corresponding commands are on the command list (or, in case of OpenGL, the - context) already. However, for APIs other than OpenGL stencil-based - clipping will need enabling stencil testing in the pipeline state that is - used by render(). - The effective opacity can be retrieved with \l inheritedOpacity(). The projection matrix is available through \a state, while the model-view @@ -156,6 +149,12 @@ QSGRenderNode::StateFlags QSGRenderNode::changedStates() const QQuickFramebufferObject, QQuickWindow::beforeRendering(), or the equivalents of those for APIs other than OpenGL. + Clip information is calculated before the function is called, it is however + not enabled. Implementations wishing to take clipping into account can set + up scissoring or stencil based on the information in \a state. Some + scenegraph backends, software in particular, use no scissor or stencil. + There the clip region is provided as an ordinary QRegion. + For OpenGL the following states are set on the render thread's context before this function is called: \list @@ -286,6 +285,19 @@ QSGRenderNode::RenderState::~RenderState() \c KEEP, comparison function \c EQUAL, and a read and write mask of \c 0xFF. */ +/*! + \fn const QRegion *QSGRenderNode::clipRegion() const + + \return the current clip region or null for backends where clipping is + implemented via stencil or scissoring. + + The software backend uses no projection, scissor or stencil, meaning most + of the render state is not in use. However, the clip region that can be set + on the QPainter still has to be communicated since reconstructing this + manually in render() is not reasonable. It can therefore be queried via + this function. + */ + /*! \return pointer to a \a state value. diff --git a/src/quick/scenegraph/coreapi/qsgrendernode.h b/src/quick/scenegraph/coreapi/qsgrendernode.h index 17569f8c59..6eb425c03b 100644 --- a/src/quick/scenegraph/coreapi/qsgrendernode.h +++ b/src/quick/scenegraph/coreapi/qsgrendernode.h @@ -68,6 +68,7 @@ public: virtual bool scissorEnabled() const = 0; virtual int stencilValue() const = 0; virtual bool stencilEnabled() const = 0; + virtual const QRegion *clipRegion() const = 0; virtual void *get(const char *state) const; }; diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp index 9574f2a48e..e219ddd82e 100644 --- a/src/quick/scenegraph/qsgadaptationlayer.cpp +++ b/src/quick/scenegraph/qsgadaptationlayer.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -512,6 +513,13 @@ void QSGNodeVisitorEx::visitChildren(QSGNode *node) visitChildren(child); break; } + case QSGNode::RenderNodeType: { + QSGRenderNode *r = static_cast(child); + if (visit(r)) + visitChildren(r); + endVisit(r); + break; + } default: Q_UNREACHABLE(); break; diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h index 00441e1544..a74b38dba8 100644 --- a/src/quick/scenegraph/qsgadaptationlayer_p.h +++ b/src/quick/scenegraph/qsgadaptationlayer_p.h @@ -82,6 +82,7 @@ class QSGInternalRectangleNode; class QSGGlyphNode; class QSGRootNode; class QSGSpriteNode; +class QSGRenderNode; class Q_QUICK_PRIVATE_EXPORT QSGNodeVisitorEx { @@ -109,6 +110,8 @@ public: virtual void endVisit(QSGRootNode *) = 0; virtual bool visit(QSGSpriteNode *) = 0; virtual void endVisit(QSGSpriteNode *) = 0; + virtual bool visit(QSGRenderNode *) = 0; + virtual void endVisit(QSGRenderNode *) = 0; void visitChildren(QSGNode *node); }; -- cgit v1.2.3