diff options
Diffstat (limited to 'src/quick/scenegraph')
102 files changed, 4284 insertions, 501 deletions
diff --git a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp index eb0e26462a..2ff180ea99 100644 --- a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp @@ -67,9 +67,7 @@ QSGAbstractSoftwareRenderer::~QSGAbstractSoftwareRenderer() // Cleanup RenderableNodes delete m_background; - for (QSGSoftwareRenderableNode *node : m_nodes.values()) { - delete node; - } + qDeleteAll(m_nodes); delete m_nodeUpdater; } @@ -149,7 +147,7 @@ void QSGAbstractSoftwareRenderer::buildRenderList() QSGSoftwareRenderListBuilder(this).visitChildren(rootNode()); } -void QSGAbstractSoftwareRenderer::optimizeRenderList() +QRegion QSGAbstractSoftwareRenderer::optimizeRenderList() { // Iterate through the renderlist from front to back // Objective is to update the dirty status and rects. @@ -212,9 +210,13 @@ void QSGAbstractSoftwareRenderer::optimizeRenderList() m_dirtyRegion += node->dirtyRegion(); } + QRegion updateRegion = m_dirtyRegion; + // Empty dirtyRegion m_dirtyRegion = QRegion(); m_obscuredRegion = QRegion(); + + return updateRegion; } void QSGAbstractSoftwareRenderer::setBackgroundColor(const QColor &color) @@ -232,7 +234,7 @@ void QSGAbstractSoftwareRenderer::setBackgroundSize(const QSize &size) m_background->setRect(0.0f, 0.0f, size.width(), size.height()); renderableNode(m_background)->markGeometryDirty(); // Invalidate the whole scene when the background is resized - m_dirtyRegion = QRegion(m_background->rect().toRect()); + markDirty(); } QColor QSGAbstractSoftwareRenderer::backgroundColor() @@ -318,4 +320,9 @@ void QSGAbstractSoftwareRenderer::nodeOpacityUpdated(QSGNode *node) m_nodeUpdater->updateNodes(node); } +void QSGAbstractSoftwareRenderer::markDirty() +{ + m_dirtyRegion = QRegion(m_background->rect().toRect()); +} + QT_END_NAMESPACE diff --git a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h index a2e953f40d..905577b92a 100644 --- a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h @@ -75,10 +75,12 @@ public: void nodeChanged(QSGNode *node, QSGNode::DirtyState state) override; + void markDirty(); + protected: QRegion renderNodes(QPainter *painter); void buildRenderList(); - void optimizeRenderList(); + QRegion optimizeRenderList(); void setBackgroundColor(const QColor &color); void setBackgroundSize(const QSize &size); diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation.cpp index 0e2f4f5382..92c02b4966 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation.cpp @@ -40,6 +40,7 @@ #include "qsgsoftwareadaptation_p.h" #include "qsgsoftwarecontext_p.h" #include "qsgsoftwarerenderloop_p.h" +#include "qsgsoftwarethreadedrenderloop_p.h" #include <private/qguiapplication_p.h> #include <qpa/qplatformintegration.h> @@ -53,7 +54,7 @@ QSGSoftwareAdaptation::QSGSoftwareAdaptation(QObject *parent) QStringList QSGSoftwareAdaptation::keys() const { - return QStringList() << QLatin1String("software"); + return QStringList() << QLatin1String("software") << QLatin1String("softwarecontext"); } QSGContext *QSGSoftwareAdaptation::create(const QString &) const @@ -73,6 +74,16 @@ QSGContextFactoryInterface::Flags QSGSoftwareAdaptation::flags(const QString &) QSGRenderLoop *QSGSoftwareAdaptation::createWindowManager() { + static bool threaded = false; + static bool envChecked = false; + if (!envChecked) { + envChecked = true; + threaded = qgetenv("QSG_RENDER_LOOP") == "threaded"; + } + + if (threaded) + return new QSGSoftwareThreadedRenderLoop; + return new QSGSoftwareRenderLoop(); } diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp index ce726e342b..80112c1121 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp @@ -39,28 +39,21 @@ #include "qsgsoftwarecontext_p.h" -#include "qsgsoftwarerectanglenode_p.h" -#include "qsgsoftwareimagenode_p.h" +#include "qsgsoftwareinternalrectanglenode_p.h" +#include "qsgsoftwareinternalimagenode_p.h" #include "qsgsoftwarepainternode_p.h" #include "qsgsoftwarepixmaptexture_p.h" #include "qsgsoftwareglyphnode_p.h" -#include "qsgsoftwareninepatchnode_p.h" +#include "qsgsoftwarepublicnodes_p.h" #include "qsgsoftwarelayer_p.h" #include "qsgsoftwarerenderer_p.h" +#include "qsgsoftwarespritenode_p.h" #include <QtCore/QCoreApplication> #include <QtCore/QElapsedTimer> #include <QtGui/QWindow> - -#include <QtQuick/QSGFlatColorMaterial> -#include <QtQuick/QSGVertexColorMaterial> -#include <QtQuick/QSGOpaqueTextureMaterial> -#include <QtQuick/QSGTextureMaterial> - -#ifndef QSG_NO_RENDERER_TIMING -static bool qsg_render_timing = !qgetenv("QSG_RENDER_TIMING").isEmpty(); -#endif +#include <QtQuick/private/qquickwindow_p.h> // Used for very high-level info about the renderering and gl context // Includes GL_VERSION, type of render loop, atlas size, etc. @@ -90,21 +83,23 @@ QT_BEGIN_NAMESPACE QSGSoftwareRenderContext::QSGSoftwareRenderContext(QSGContext *ctx) : QSGRenderContext(ctx) , m_initialized(false) + , m_activePainter(nullptr) { } + QSGSoftwareContext::QSGSoftwareContext(QObject *parent) : QSGContext(parent) { } -QSGRectangleNode *QSGSoftwareContext::createRectangleNode() +QSGInternalRectangleNode *QSGSoftwareContext::createInternalRectangleNode() { - return new QSGSoftwareRectangleNode(); + return new QSGSoftwareInternalRectangleNode(); } -QSGImageNode *QSGSoftwareContext::createImageNode() +QSGInternalImageNode *QSGSoftwareContext::createInternalImageNode() { - return new QSGSoftwareImageNode(); + return new QSGSoftwareInternalImageNode(); } QSGPainterNode *QSGSoftwareContext::createPainterNode(QQuickPaintedItem *item) @@ -119,11 +114,6 @@ QSGGlyphNode *QSGSoftwareContext::createGlyphNode(QSGRenderContext *rc, bool pre return new QSGSoftwareGlyphNode(); } -QSGNinePatchNode *QSGSoftwareContext::createNinePatchNode() -{ - return new QSGSoftwareNinePatchNode(); -} - QSGLayer *QSGSoftwareContext::createLayer(QSGRenderContext *renderContext) { return new QSGSoftwareLayer(renderContext); @@ -148,7 +138,8 @@ void QSGSoftwareRenderContext::initializeIfNeeded() void QSGSoftwareRenderContext::invalidate() { - QSGRenderContext::invalidate(); + m_sg->renderContextInvalidated(this); + emit invalidated(); } QSGTexture *QSGSoftwareRenderContext::createTexture(const QImage &image, uint flags) const @@ -167,12 +158,37 @@ void QSGSoftwareRenderContext::renderNextFrame(QSGRenderer *renderer, uint fbo) renderer->renderScene(fbo); } +int QSGSoftwareRenderContext::maxTextureSize() const +{ + return 2048; +} + QSGRendererInterface *QSGSoftwareContext::rendererInterface(QSGRenderContext *renderContext) { Q_UNUSED(renderContext); return this; } +QSGRectangleNode *QSGSoftwareContext::createRectangleNode() +{ + return new QSGSoftwareRectangleNode; +} + +QSGImageNode *QSGSoftwareContext::createImageNode() +{ + return new QSGSoftwareImageNode; +} + +QSGNinePatchNode *QSGSoftwareContext::createNinePatchNode() +{ + return new QSGSoftwareNinePatchNode; +} + +QSGSpriteNode *QSGSoftwareContext::createSpriteNode() +{ + return new QSGSoftwareSpriteNode; +} + QSGRendererInterface::GraphicsApi QSGSoftwareContext::graphicsApi() const { return Software; @@ -193,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<QSGSoftwareRenderContext *>(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 992f6f5677..dcc137b4b4 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h @@ -75,8 +75,10 @@ public: void renderNextFrame(QSGRenderer *renderer, uint fbo) override; QSGTexture *createTexture(const QImage &image, uint flags = CreateTexture_Alpha) const override; QSGRenderer *createRenderer() override; + int maxTextureSize() const override; bool m_initialized; + QPainter *m_activePainter; }; class QSGSoftwareContext : public QSGContext, public QSGRendererInterface @@ -86,19 +88,23 @@ public: explicit QSGSoftwareContext(QObject *parent = nullptr); QSGRenderContext *createRenderContext() override { return new QSGSoftwareRenderContext(this); } - QSGRectangleNode *createRectangleNode() override; - QSGImageNode *createImageNode() override; + QSGInternalRectangleNode *createInternalRectangleNode() override; + QSGInternalImageNode *createInternalImageNode() override; QSGPainterNode *createPainterNode(QQuickPaintedItem *item) override; QSGGlyphNode *createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode) override; - QSGNinePatchNode *createNinePatchNode() override; QSGLayer *createLayer(QSGRenderContext *renderContext) override; QSurfaceFormat defaultSurfaceFormat() const override; QSGRendererInterface *rendererInterface(QSGRenderContext *renderContext) override; + QSGRectangleNode *createRectangleNode() override; + QSGImageNode *createImageNode() override; + QSGNinePatchNode *createNinePatchNode() override; + QSGSpriteNode *createSpriteNode() override; GraphicsApi graphicsApi() const override; 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/qsgsoftwareimagenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp index 7dadc1d3d4..10291b9cb5 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwareimagenode.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp @@ -37,7 +37,7 @@ ** ****************************************************************************/ -#include "qsgsoftwareimagenode_p.h" +#include "qsgsoftwareinternalimagenode_p.h" #include "qsgsoftwarepixmaptexture_p.h" #include "qsgsoftwarelayer_p.h" @@ -315,7 +315,7 @@ void qDrawBorderPixmap(QPainter *painter, const QRect &targetRect, const QMargin } // QSGSoftwareHelpers namespace -QSGSoftwareImageNode::QSGSoftwareImageNode() +QSGSoftwareInternalImageNode::QSGSoftwareInternalImageNode() : m_innerSourceRect(0, 0, 1, 1) , m_subSourceRect(0, 0, 1, 1) , m_texture(0) @@ -330,7 +330,7 @@ QSGSoftwareImageNode::QSGSoftwareImageNode() } -void QSGSoftwareImageNode::setTargetRect(const QRectF &rect) +void QSGSoftwareInternalImageNode::setTargetRect(const QRectF &rect) { if (rect == m_targetRect) return; @@ -338,7 +338,7 @@ void QSGSoftwareImageNode::setTargetRect(const QRectF &rect) markDirty(DirtyGeometry); } -void QSGSoftwareImageNode::setInnerTargetRect(const QRectF &rect) +void QSGSoftwareInternalImageNode::setInnerTargetRect(const QRectF &rect) { if (rect == m_innerTargetRect) return; @@ -346,7 +346,7 @@ void QSGSoftwareImageNode::setInnerTargetRect(const QRectF &rect) markDirty(DirtyGeometry); } -void QSGSoftwareImageNode::setInnerSourceRect(const QRectF &rect) +void QSGSoftwareInternalImageNode::setInnerSourceRect(const QRectF &rect) { if (rect == m_innerSourceRect) return; @@ -354,7 +354,7 @@ void QSGSoftwareImageNode::setInnerSourceRect(const QRectF &rect) markDirty(DirtyGeometry); } -void QSGSoftwareImageNode::setSubSourceRect(const QRectF &rect) +void QSGSoftwareInternalImageNode::setSubSourceRect(const QRectF &rect) { if (rect == m_subSourceRect) return; @@ -362,16 +362,14 @@ void QSGSoftwareImageNode::setSubSourceRect(const QRectF &rect) markDirty(DirtyGeometry); } -void QSGSoftwareImageNode::setTexture(QSGTexture *texture) +void QSGSoftwareInternalImageNode::setTexture(QSGTexture *texture) { - if (m_texture != texture) { - m_texture = texture; - m_cachedMirroredPixmapIsDirty = true; - markDirty(DirtyMaterial); - } + m_texture = texture; + m_cachedMirroredPixmapIsDirty = true; + markDirty(DirtyMaterial); } -void QSGSoftwareImageNode::setMirror(bool mirror) +void QSGSoftwareInternalImageNode::setMirror(bool mirror) { if (m_mirror != mirror) { m_mirror = mirror; @@ -380,11 +378,11 @@ void QSGSoftwareImageNode::setMirror(bool mirror) } } -void QSGSoftwareImageNode::setMipmapFiltering(QSGTexture::Filtering /*filtering*/) +void QSGSoftwareInternalImageNode::setMipmapFiltering(QSGTexture::Filtering /*filtering*/) { } -void QSGSoftwareImageNode::setFiltering(QSGTexture::Filtering filtering) +void QSGSoftwareInternalImageNode::setFiltering(QSGTexture::Filtering filtering) { bool smooth = (filtering == QSGTexture::Linear); if (smooth == m_smooth) @@ -394,7 +392,7 @@ void QSGSoftwareImageNode::setFiltering(QSGTexture::Filtering filtering) markDirty(DirtyMaterial); } -void QSGSoftwareImageNode::setHorizontalWrapMode(QSGTexture::WrapMode wrapMode) +void QSGSoftwareInternalImageNode::setHorizontalWrapMode(QSGTexture::WrapMode wrapMode) { bool tileHorizontal = (wrapMode == QSGTexture::Repeat); if (tileHorizontal == m_tileHorizontal) @@ -404,7 +402,7 @@ void QSGSoftwareImageNode::setHorizontalWrapMode(QSGTexture::WrapMode wrapMode) markDirty(DirtyMaterial); } -void QSGSoftwareImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrapMode) +void QSGSoftwareInternalImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrapMode) { bool tileVertical = (wrapMode == QSGTexture::Repeat); if (tileVertical == m_tileVertical) @@ -414,7 +412,7 @@ void QSGSoftwareImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrapMode) markDirty(DirtyMaterial); } -void QSGSoftwareImageNode::update() +void QSGSoftwareInternalImageNode::update() { if (m_cachedMirroredPixmapIsDirty) { if (m_mirror) { @@ -428,7 +426,7 @@ void QSGSoftwareImageNode::update() } } -void QSGSoftwareImageNode::preprocess() +void QSGSoftwareInternalImageNode::preprocess() { bool doDirty = false; QSGLayer *t = qobject_cast<QSGLayer *>(m_texture); @@ -452,7 +450,7 @@ static Qt::TileRule getTileRule(qreal factor) } -void QSGSoftwareImageNode::paint(QPainter *painter) +void QSGSoftwareInternalImageNode::paint(QPainter *painter) { painter->setRenderHint(QPainter::SmoothPixmapTransform, m_smooth); @@ -485,12 +483,12 @@ void QSGSoftwareImageNode::paint(QPainter *painter) } } -QRectF QSGSoftwareImageNode::rect() const +QRectF QSGSoftwareInternalImageNode::rect() const { return m_targetRect; } -const QPixmap &QSGSoftwareImageNode::pixmap() const +const QPixmap &QSGSoftwareInternalImageNode::pixmap() const { if (QSGSoftwarePixmapTexture *pt = qobject_cast<QSGSoftwarePixmapTexture*>(m_texture)) { return pt->pixmap(); diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareimagenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h index e42f616757..f21667fdf7 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwareimagenode_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h @@ -37,8 +37,8 @@ ** ****************************************************************************/ -#ifndef QSGSOFTWAREIMAGENODE_H -#define QSGSOFTWAREIMAGENODE_H +#ifndef QSGSOFTWAREINTERNALIMAGENODE_H +#define QSGSOFTWAREINTERNALIMAGENODE_H // // W A R N I N G @@ -101,10 +101,10 @@ void qDrawBorderPixmap(QPainter *painter, const QRect &targetRect, const QMargin } // QSGSoftwareHelpers namespace -class QSGSoftwareImageNode : public QSGImageNode +class QSGSoftwareInternalImageNode : public QSGInternalImageNode { public: - QSGSoftwareImageNode(); + QSGSoftwareInternalImageNode(); void setTargetRect(const QRectF &rect) override; void setInnerTargetRect(const QRectF &rect) override; @@ -144,4 +144,4 @@ private: QT_END_NAMESPACE -#endif // QSGSOFTWAREIMAGENODE_H +#endif // QSGSOFTWAREINTERNALIMAGENODE_H diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerectanglenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode.cpp index 7672b14371..f6898b3879 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerectanglenode.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode.cpp @@ -37,14 +37,14 @@ ** ****************************************************************************/ -#include "qsgsoftwarerectanglenode_p.h" +#include "qsgsoftwareinternalrectanglenode_p.h" #include <qmath.h> #include <QtGui/QPainter> QT_BEGIN_NAMESPACE -QSGSoftwareRectangleNode::QSGSoftwareRectangleNode() +QSGSoftwareInternalRectangleNode::QSGSoftwareInternalRectangleNode() : m_penWidth(0) , m_radius(0) , m_cornerPixmapIsDirty(true) @@ -56,7 +56,7 @@ QSGSoftwareRectangleNode::QSGSoftwareRectangleNode() setGeometry((QSGGeometry*)1); } -void QSGSoftwareRectangleNode::setRect(const QRectF &rect) +void QSGSoftwareInternalRectangleNode::setRect(const QRectF &rect) { QRect alignedRect = rect.toAlignedRect(); if (m_rect != alignedRect) { @@ -65,7 +65,7 @@ void QSGSoftwareRectangleNode::setRect(const QRectF &rect) } } -void QSGSoftwareRectangleNode::setColor(const QColor &color) +void QSGSoftwareInternalRectangleNode::setColor(const QColor &color) { if (m_color != color) { m_color = color; @@ -74,7 +74,7 @@ void QSGSoftwareRectangleNode::setColor(const QColor &color) } } -void QSGSoftwareRectangleNode::setPenColor(const QColor &color) +void QSGSoftwareInternalRectangleNode::setPenColor(const QColor &color) { if (m_penColor != color) { m_penColor = color; @@ -83,7 +83,7 @@ void QSGSoftwareRectangleNode::setPenColor(const QColor &color) } } -void QSGSoftwareRectangleNode::setPenWidth(qreal width) +void QSGSoftwareInternalRectangleNode::setPenWidth(qreal width) { if (m_penWidth != width) { m_penWidth = width; @@ -113,11 +113,11 @@ static QGradientStop interpolateStop(const QGradientStop &firstStop, const QGrad return newStop; } -void QSGSoftwareRectangleNode::setGradientStops(const QGradientStops &stops) +void QSGSoftwareInternalRectangleNode::setGradientStops(const QGradientStops &stops) { //normalize stops bool needsNormalization = false; - foreach (const QGradientStop &stop, stops) { + for (const QGradientStop &stop : qAsConst(stops)) { if (stop.first < 0.0 || stop.first > 1.0) { needsNormalization = true; continue; @@ -186,7 +186,7 @@ void QSGSoftwareRectangleNode::setGradientStops(const QGradientStops &stops) markDirty(DirtyMaterial); } -void QSGSoftwareRectangleNode::setRadius(qreal radius) +void QSGSoftwareInternalRectangleNode::setRadius(qreal radius) { if (m_radius != radius) { m_radius = radius; @@ -195,11 +195,11 @@ void QSGSoftwareRectangleNode::setRadius(qreal radius) } } -void QSGSoftwareRectangleNode::setAligned(bool /*aligned*/) +void QSGSoftwareInternalRectangleNode::setAligned(bool /*aligned*/) { } -void QSGSoftwareRectangleNode::update() +void QSGSoftwareInternalRectangleNode::update() { if (!m_penWidth || m_penColor == Qt::transparent) { m_pen = Qt::NoPen; @@ -223,7 +223,7 @@ void QSGSoftwareRectangleNode::update() } } -void QSGSoftwareRectangleNode::paint(QPainter *painter) +void QSGSoftwareInternalRectangleNode::paint(QPainter *painter) { //We can only check for a device pixel ratio change when we know what //paint device is being used. @@ -265,7 +265,7 @@ void QSGSoftwareRectangleNode::paint(QPainter *painter) } -bool QSGSoftwareRectangleNode::isOpaque() const +bool QSGSoftwareInternalRectangleNode::isOpaque() const { if (m_radius > 0.0f) return false; @@ -274,7 +274,7 @@ bool QSGSoftwareRectangleNode::isOpaque() const if (m_penWidth > 0.0f && m_penColor.alpha() < 255) return false; if (m_stops.count() > 0) { - foreach (QGradientStop stop, m_stops) { + for (const QGradientStop &stop : qAsConst(m_stops)) { if (stop.second.alpha() < 255) return false; } @@ -283,13 +283,13 @@ bool QSGSoftwareRectangleNode::isOpaque() const return true; } -QRectF QSGSoftwareRectangleNode::rect() const +QRectF QSGSoftwareInternalRectangleNode::rect() const { //TODO: double check that this is correct. return m_rect; } -void QSGSoftwareRectangleNode::paintRectangle(QPainter *painter, const QRect &rect) +void QSGSoftwareInternalRectangleNode::paintRectangle(QPainter *painter, const QRect &rect) { //Radius should never exceeds half of the width or half of the height int radius = qFloor(qMin(qMin(rect.width(), rect.height()) * 0.5, m_radius)); @@ -411,7 +411,7 @@ void QSGSoftwareRectangleNode::paintRectangle(QPainter *painter, const QRect &re painter->setRenderHints(previousRenderHints); } -void QSGSoftwareRectangleNode::generateCornerPixmap() +void QSGSoftwareInternalRectangleNode::generateCornerPixmap() { //Generate new corner Pixmap int radius = qFloor(qMin(qMin(m_rect.width(), m_rect.height()) * 0.5, m_radius)); diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerectanglenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode_p.h index 9cc0823325..f363e279e1 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerectanglenode_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode_p.h @@ -37,8 +37,8 @@ ** ****************************************************************************/ -#ifndef QSGSOFTWARERECTANGLENODE_H -#define QSGSOFTWARERECTANGLENODE_H +#ifndef QSGSOFTWAREINTERNALRECTANGLENODE_H +#define QSGSOFTWAREINTERNALRECTANGLENODE_H // // W A R N I N G @@ -59,10 +59,10 @@ QT_BEGIN_NAMESPACE -class QSGSoftwareRectangleNode : public QSGRectangleNode +class QSGSoftwareInternalRectangleNode : public QSGInternalRectangleNode { public: - QSGSoftwareRectangleNode(); + QSGSoftwareInternalRectangleNode(); void setRect(const QRectF &rect) override; void setColor(const QColor &color) override; @@ -100,4 +100,4 @@ private: QT_END_NAMESPACE -#endif // QSGSOFTWARERECTANGLENODE_H +#endif // QSGSOFTWAREINTERNALRECTANGLENODE_H 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 <QtQuick/QSGSimpleRectNode> @@ -84,6 +85,9 @@ void QSGSoftwarePixmapRenderer::render(QPaintDevice *target) QPainter painter(target); painter.setRenderHint(QPainter::Antialiasing); painter.setWindow(m_projectionRect); + auto rc = static_cast<QSGSoftwareRenderContext *>(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/qsgsoftwareninepatchnode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp index 36ff1f2229..1fa5234377 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwareninepatchnode.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp @@ -37,12 +37,99 @@ ** ****************************************************************************/ -#include "qsgsoftwareninepatchnode_p.h" +#include "qsgsoftwarepublicnodes_p.h" #include "qsgsoftwarepixmaptexture_p.h" -#include "qsgsoftwareimagenode_p.h" +#include "qsgsoftwareinternalimagenode_p.h" QT_BEGIN_NAMESPACE +QSGSoftwareRectangleNode::QSGSoftwareRectangleNode() + : m_color(QColor(255, 255, 255)) +{ + setMaterial((QSGMaterial*)1); + setGeometry((QSGGeometry*)1); +} + +void QSGSoftwareRectangleNode::paint(QPainter *painter) +{ + painter->fillRect(m_rect, m_color); +} + +QSGSoftwareImageNode::QSGSoftwareImageNode() + : m_texture(nullptr), + m_owns(false), + m_filtering(QSGTexture::None), + m_transformMode(NoTransform), + m_cachedMirroredPixmapIsDirty(false) +{ + setMaterial((QSGMaterial*)1); + setGeometry((QSGGeometry*)1); +} + +QSGSoftwareImageNode::~QSGSoftwareImageNode() +{ + if (m_owns) + delete m_texture; +} + +void QSGSoftwareImageNode::setTexture(QSGTexture *texture) +{ + m_texture = texture; markDirty(DirtyMaterial); + m_cachedMirroredPixmapIsDirty = true; +} + +void QSGSoftwareImageNode::setTextureCoordinatesTransform(QSGImageNode::TextureCoordinatesTransformMode transformNode) +{ + if (m_transformMode == transformNode) + return; + + m_transformMode = transformNode; + m_cachedMirroredPixmapIsDirty = true; + + markDirty(DirtyGeometry); +} + +void QSGSoftwareImageNode::paint(QPainter *painter) +{ + if (m_cachedMirroredPixmapIsDirty) + updateCachedMirroredPixmap(); + + painter->setRenderHint(QPainter::SmoothPixmapTransform, (m_filtering == QSGTexture::Linear)); + + if (!m_cachedPixmap.isNull()) { + painter->drawPixmap(m_rect, m_cachedPixmap, m_sourceRect); + } else if (QSGSoftwarePixmapTexture *pt = dynamic_cast<QSGSoftwarePixmapTexture *>(m_texture)) { + const QPixmap &pm = pt->pixmap(); + painter->drawPixmap(m_rect, pm, m_sourceRect); + } else if (QSGPlainTexture *pt = dynamic_cast<QSGPlainTexture *>(m_texture)) { + const QImage &im = pt->image(); + painter->drawImage(m_rect, im, m_sourceRect); + } +} + +void QSGSoftwareImageNode::updateCachedMirroredPixmap() +{ + if (m_transformMode == NoTransform) { + m_cachedPixmap = QPixmap(); + } else { + + if (QSGSoftwarePixmapTexture *pt = dynamic_cast<QSGSoftwarePixmapTexture *>(m_texture)) { + QTransform mirrorTransform; + if (m_transformMode.testFlag(MirrorVertically)) + mirrorTransform = mirrorTransform.scale(1, -1); + if (m_transformMode.testFlag(MirrorHorizontally)) + mirrorTransform = mirrorTransform.scale(-1, 1); + m_cachedPixmap = pt->pixmap().transformed(mirrorTransform); + } else if (QSGPlainTexture *pt = dynamic_cast<QSGPlainTexture *>(m_texture)) { + m_cachedPixmap = QPixmap::fromImage(pt->image().mirrored(m_transformMode.testFlag(MirrorHorizontally), m_transformMode.testFlag(MirrorVertically))); + } else { + m_cachedPixmap = QPixmap(); + } + } + + m_cachedMirroredPixmapIsDirty = false; +} + QSGSoftwareNinePatchNode::QSGSoftwareNinePatchNode() { setMaterial((QSGMaterial*)1); diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes_p.h new file mode 100644 index 0000000000..9f1913205b --- /dev/null +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes_p.h @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGSOFTWAREPUBLICNODES_H +#define QSGSOFTWAREPUBLICNODES_H + +#include <QtQuick/qsgrectanglenode.h> +#include <QtQuick/qsgimagenode.h> +#include <QtQuick/qsgninepatchnode.h> +#include <QtGui/qpixmap.h> + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt 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. +// + +QT_BEGIN_NAMESPACE + +class QSGSoftwareRectangleNode : public QSGRectangleNode +{ +public: + QSGSoftwareRectangleNode(); + + void setRect(const QRectF &rect) override { m_rect = rect; markDirty(DirtyMaterial); } + QRectF rect() const override { return m_rect; } + + void setColor(const QColor &color) override { m_color = color; markDirty(DirtyMaterial); } + QColor color() const override { return m_color; } + + void paint(QPainter *painter); + +private: + QRectF m_rect; + QColor m_color; +}; + +class QSGSoftwareImageNode : public QSGImageNode +{ +public: + QSGSoftwareImageNode(); + ~QSGSoftwareImageNode(); + + void setRect(const QRectF &rect) override { m_rect = rect; markDirty(DirtyMaterial); } + QRectF rect() const override { return m_rect; } + + void setSourceRect(const QRectF &r) override { m_sourceRect = r; } + QRectF sourceRect() const override { return m_sourceRect; } + + void setTexture(QSGTexture *texture) override; + QSGTexture *texture() const override { return m_texture; } + + void setFiltering(QSGTexture::Filtering filtering) override { m_filtering = filtering; markDirty(DirtyMaterial); } + QSGTexture::Filtering filtering() const override { return m_filtering; } + + void setMipmapFiltering(QSGTexture::Filtering) override { } + QSGTexture::Filtering mipmapFiltering() const override { return QSGTexture::None; } + + void setTextureCoordinatesTransform(TextureCoordinatesTransformMode transformNode) override; + TextureCoordinatesTransformMode textureCoordinatesTransform() const override { return m_transformMode; } + + void setOwnsTexture(bool owns) override { m_owns = owns; } + bool ownsTexture() const override { return m_owns; } + + void paint(QPainter *painter); + +private: + void updateCachedMirroredPixmap(); + + QPixmap m_cachedPixmap; + QSGTexture *m_texture; + QRectF m_rect; + QRectF m_sourceRect; + bool m_owns; + QSGTexture::Filtering m_filtering; + TextureCoordinatesTransformMode m_transformMode; + bool m_cachedMirroredPixmapIsDirty; +}; + +class QSGSoftwareNinePatchNode : public QSGNinePatchNode +{ +public: + QSGSoftwareNinePatchNode(); + + void setTexture(QSGTexture *texture) override; + void setBounds(const QRectF &bounds) override; + void setDevicePixelRatio(qreal ratio) override; + void setPadding(qreal left, qreal top, qreal right, qreal bottom) override; + void update() override; + + void paint(QPainter *painter); + + QRectF bounds() const; + +private: + QPixmap m_pixmap; + QRectF m_bounds; + qreal m_pixelRatio; + QMargins m_margins; +}; + +QT_END_NAMESPACE + +#endif // QSGSOFTWAREPUBLICNODES_H diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp index 063242c63b..7b9e749532 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp @@ -39,15 +39,17 @@ #include "qsgsoftwarerenderablenode_p.h" -#include "qsgsoftwareimagenode_p.h" -#include "qsgsoftwarerectanglenode_p.h" +#include "qsgsoftwareinternalimagenode_p.h" +#include "qsgsoftwareinternalrectanglenode_p.h" #include "qsgsoftwareglyphnode_p.h" -#include "qsgsoftwareninepatchnode_p.h" +#include "qsgsoftwarepublicnodes_p.h" #include "qsgsoftwarepainternode_p.h" #include "qsgsoftwarepixmaptexture_p.h" +#include "qsgsoftwarespritenode_p.h" -#include <QtQuick/QSGSimpleRectNode> -#include <QtQuick/qsgsimpletexturenode.h> +#include <qsgsimplerectnode.h> +#include <qsgsimpletexturenode.h> +#include <private/qsgrendernode_p.h> #include <private/qsgtexture_p.h> Q_LOGGING_CATEGORY(lcRenderable, "qt.scenegraph.softwarecontext.renderable") @@ -58,6 +60,7 @@ QSGSoftwareRenderableNode::QSGSoftwareRenderableNode(NodeType type, QSGNode *nod : m_nodeType(type) , m_isOpaque(true) , m_isDirty(true) + , m_hasClipRegion(false) , m_opacity(1.0f) { switch (m_nodeType) { @@ -68,13 +71,13 @@ QSGSoftwareRenderableNode::QSGSoftwareRenderableNode(NodeType type, QSGNode *nod m_handle.simpleTextureNode = static_cast<QSGSimpleTextureNode*>(node); break; case QSGSoftwareRenderableNode::Image: - m_handle.imageNode = static_cast<QSGSoftwareImageNode*>(node); + m_handle.imageNode = static_cast<QSGSoftwareInternalImageNode*>(node); break; case QSGSoftwareRenderableNode::Painter: m_handle.painterNode = static_cast<QSGSoftwarePainterNode*>(node); break; case QSGSoftwareRenderableNode::Rectangle: - m_handle.rectangleNode = static_cast<QSGSoftwareRectangleNode*>(node); + m_handle.rectangleNode = static_cast<QSGSoftwareInternalRectangleNode*>(node); break; case QSGSoftwareRenderableNode::Glyph: m_handle.glpyhNode = static_cast<QSGSoftwareGlyphNode*>(node); @@ -82,6 +85,18 @@ QSGSoftwareRenderableNode::QSGSoftwareRenderableNode(NodeType type, QSGNode *nod case QSGSoftwareRenderableNode::NinePatch: m_handle.ninePatchNode = static_cast<QSGSoftwareNinePatchNode*>(node); break; + case QSGSoftwareRenderableNode::SimpleRectangle: + m_handle.simpleRectangleNode = static_cast<QSGRectangleNode*>(node); + break; + case QSGSoftwareRenderableNode::SimpleImage: + m_handle.simpleImageNode = static_cast<QSGImageNode*>(node); + break; + case QSGSoftwareRenderableNode::SpriteNode: + m_handle.spriteNode = static_cast<QSGSoftwareSpriteNode*>(node); + break; + case QSGSoftwareRenderableNode::RenderNode: + m_handle.renderNode = static_cast<QSGRenderNode*>(node); + break; case QSGSoftwareRenderableNode::Invalid: m_handle.simpleRectNode = nullptr; break; @@ -151,14 +166,46 @@ void QSGSoftwareRenderableNode::update() boundingRect = m_handle.ninePatchNode->bounds().toRect(); break; + case QSGSoftwareRenderableNode::SimpleRectangle: + if (m_handle.simpleRectangleNode->color().alpha() == 255 && !m_transform.isRotating()) + m_isOpaque = true; + else + m_isOpaque = false; + + boundingRect = m_handle.simpleRectangleNode->rect().toRect(); + break; + case QSGSoftwareRenderableNode::SimpleImage: + if (!m_handle.simpleImageNode->texture()->hasAlphaChannel() && !m_transform.isRotating()) + m_isOpaque = true; + else + m_isOpaque = false; + + boundingRect = m_handle.simpleImageNode->rect().toRect(); + break; + case QSGSoftwareRenderableNode::SpriteNode: + m_isOpaque = m_handle.spriteNode->isOpaque(); + boundingRect = m_handle.spriteNode->rect().toRect(); + break; + case QSGSoftwareRenderableNode::RenderNode: + if (m_handle.renderNode->flags().testFlag(QSGRenderNode::OpaqueRendering) && !m_transform.isRotating()) + m_isOpaque = true; + else + m_isOpaque = false; + + boundingRect = m_handle.renderNode->rect().toRect(); + break; default: break; } m_boundingRect = m_transform.mapRect(boundingRect); - if (m_clipRegion.rectCount() == 1) { - m_boundingRect = m_boundingRect.intersected(m_clipRegion.rects().first()); + if (m_hasClipRegion && m_clipRegion.rectCount() <= 1) { + // If there is a clipRegion, and it is empty, the item wont be rendered + if (m_clipRegion.isEmpty()) + m_boundingRect = QRect(); + else + m_boundingRect = m_boundingRect.intersected(m_clipRegion.rects().first()); } // Overrides @@ -168,15 +215,56 @@ void QSGSoftwareRenderableNode::update() m_dirtyRegion = QRegion(m_boundingRect); } +struct RenderNodeState : public QSGRenderNode::RenderState +{ + const QMatrix4x4 *projectionMatrix() const override { return &ident; } + QRect scissorRect() const override { return QRect(); } + bool scissorEnabled() const override { return false; } + int stencilValue() const override { return 0; } + bool stencilEnabled() const override { return false; } + const QRegion *clipRegion() const override { 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; + + const QRect br = m_handle.renderNode->flags().testFlag(QSGRenderNode::BoundedRectRendering) + ? m_boundingRect : + QRect(0, 0, painter->device()->width(), painter->device()->height()); + + painter->save(); + painter->setClipRegion(br, Qt::ReplaceClip); + m_handle.renderNode->render(&rs); + painter->restore(); + + m_previousDirtyRegion = QRegion(br); + m_isDirty = false; + m_dirtyRegion = QRegion(); + return br; + } } painter->save(); @@ -201,10 +289,10 @@ QRegion QSGSoftwareRenderableNode::renderNode(QPainter *painter, bool forceOpaqu QSGTexture *texture = m_handle.simpleTextureNode->texture(); if (QSGSoftwarePixmapTexture *pt = dynamic_cast<QSGSoftwarePixmapTexture *>(texture)) { const QPixmap &pm = pt->pixmap(); - painter->drawPixmap(m_handle.simpleTextureNode->rect(), pm, QRectF(0, 0, pm.width(), pm.height())); + painter->drawPixmap(m_handle.simpleTextureNode->rect(), pm, m_handle.simpleTextureNode->sourceRect()); } else if (QSGPlainTexture *pt = dynamic_cast<QSGPlainTexture *>(texture)) { const QImage &im = pt->image(); - painter->drawImage(m_handle.simpleTextureNode->rect(), im, QRectF(0, 0, im.width(), im.height())); + painter->drawImage(m_handle.simpleTextureNode->rect(), im, m_handle.simpleTextureNode->sourceRect()); } } break; @@ -223,6 +311,15 @@ QRegion QSGSoftwareRenderableNode::renderNode(QPainter *painter, bool forceOpaqu case QSGSoftwareRenderableNode::NinePatch: m_handle.ninePatchNode->paint(painter); break; + case QSGSoftwareRenderableNode::SimpleRectangle: + static_cast<QSGSoftwareRectangleNode *>(m_handle.simpleRectangleNode)->paint(painter); + break; + case QSGSoftwareRenderableNode::SimpleImage: + static_cast<QSGSoftwareImageNode *>(m_handle.simpleImageNode)->paint(painter); + break; + case QSGSoftwareRenderableNode::SpriteNode: + static_cast<QSGSoftwareSpriteNode *>(m_handle.spriteNode)->paint(painter); + break; default: break; } @@ -256,12 +353,13 @@ void QSGSoftwareRenderableNode::setTransform(const QTransform &transform) update(); } -void QSGSoftwareRenderableNode::setClipRegion(const QRegion &clipRect) +void QSGSoftwareRenderableNode::setClipRegion(const QRegion &clipRect, bool hasClipRegion) { - if (m_clipRegion == clipRect) + if (m_clipRegion == clipRect && m_hasClipRegion == hasClipRegion) return; m_clipRegion = clipRect; + m_hasClipRegion = hasClipRegion; update(); } diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h index 9a5e0a5683..0626b1e657 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h @@ -54,17 +54,21 @@ #include <QtGui/QRegion> #include <QtCore/QRect> #include <QtGui/QTransform> +#include <QtQuick/qsgrectanglenode.h> +#include <QtQuick/qsgimagenode.h> +#include <QtQuick/qsgninepatchnode.h> QT_BEGIN_NAMESPACE -class QSGNode; class QSGSimpleRectNode; class QSGSimpleTextureNode; -class QSGSoftwareImageNode; +class QSGSoftwareInternalImageNode; class QSGSoftwarePainterNode; -class QSGSoftwareRectangleNode; +class QSGSoftwareInternalRectangleNode; class QSGSoftwareGlyphNode; class QSGSoftwareNinePatchNode; +class QSGSoftwareSpriteNode; +class QSGRenderNode; class QSGSoftwareRenderableNode { @@ -77,7 +81,11 @@ public: Painter, Rectangle, Glyph, - NinePatch + NinePatch, + SimpleRectangle, + SimpleImage, + SpriteNode, + RenderNode }; QSGSoftwareRenderableNode(NodeType type, QSGNode *node); @@ -93,7 +101,7 @@ public: bool isDirtyRegionEmpty() const; void setTransform(const QTransform &transform); - void setClipRegion(const QRegion &clipRegion); + void setClipRegion(const QRegion &clipRegion, bool hasClipRegion = true); void setOpacity(float opacity); QTransform transform() const { return m_transform; } QRegion clipRegion() const { return m_clipRegion; } @@ -112,11 +120,15 @@ private: union RenderableNodeHandle { QSGSimpleRectNode *simpleRectNode; QSGSimpleTextureNode *simpleTextureNode; - QSGSoftwareImageNode *imageNode; + QSGSoftwareInternalImageNode *imageNode; QSGSoftwarePainterNode *painterNode; - QSGSoftwareRectangleNode *rectangleNode; + QSGSoftwareInternalRectangleNode *rectangleNode; QSGSoftwareGlyphNode *glpyhNode; QSGSoftwareNinePatchNode *ninePatchNode; + QSGRectangleNode *simpleRectangleNode; + QSGImageNode *simpleImageNode; + QSGSoftwareSpriteNode *spriteNode; + QSGRenderNode *renderNode; }; const NodeType m_nodeType; @@ -130,6 +142,7 @@ private: QTransform m_transform; QRegion m_clipRegion; + bool m_hasClipRegion; float m_opacity; QRect m_boundingRect; diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp index 3d5fe21f7c..12dbf63353 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp @@ -40,15 +40,16 @@ #include "qsgsoftwarerenderablenodeupdater_p.h" #include "qsgabstractsoftwarerenderer_p.h" -#include "qsgsoftwareimagenode_p.h" -#include "qsgsoftwarerectanglenode_p.h" +#include "qsgsoftwareinternalimagenode_p.h" +#include "qsgsoftwareinternalrectanglenode_p.h" #include "qsgsoftwareglyphnode_p.h" -#include "qsgsoftwareninepatchnode_p.h" +#include "qsgsoftwarepublicnodes_p.h" #include "qsgsoftwarepainternode_p.h" #include "qsgsoftwarepixmaptexture_p.h" -#include <QtQuick/QSGSimpleRectNode> +#include <QtQuick/qsgsimplerectnode.h> #include <QtQuick/qsgsimpletexturenode.h> +#include <QtQuick/qsgrendernode.h> QT_BEGIN_NAMESPACE @@ -58,6 +59,7 @@ QSGSoftwareRenderableNodeUpdater::QSGSoftwareRenderableNodeUpdater(QSGAbstractSo m_opacityState.push(1.0f); // Invalid RectF by default for no clip m_clipState.push(QRegion()); + m_hasClip = false; m_transformState.push(QTransform()); } @@ -81,10 +83,13 @@ void QSGSoftwareRenderableNodeUpdater::endVisit(QSGTransformNode *) bool QSGSoftwareRenderableNodeUpdater::visit(QSGClipNode *node) { // Make sure to translate the clip rect into world coordinates - if (m_clipState.top().isEmpty()) { + if (m_clipState.count() == 1) { m_clipState.push(m_transformState.top().map(QRegion(node->clipRect().toRect()))); - } else - m_clipState.push(m_transformState.top().map(QRegion(node->clipRect().toRect()).intersected(m_clipState.top()))); + m_hasClip = true; + } else { + const QRegion transformedClipRect = m_transformState.top().map(QRegion(node->clipRect().toRect())); + m_clipState.push(transformedClipRect.intersected(m_clipState.top())); + } m_stateMap[node] = currentState(node); return true; } @@ -92,6 +97,8 @@ bool QSGSoftwareRenderableNodeUpdater::visit(QSGClipNode *node) void QSGSoftwareRenderableNodeUpdater::endVisit(QSGClipNode *) { m_clipState.pop(); + if (m_clipState.count() == 1) + m_hasClip = false; } bool QSGSoftwareRenderableNodeUpdater::visit(QSGGeometryNode *node) @@ -100,6 +107,12 @@ bool QSGSoftwareRenderableNodeUpdater::visit(QSGGeometryNode *node) return updateRenderableNode(QSGSoftwareRenderableNode::SimpleRect, rectNode); } else if (QSGSimpleTextureNode *tn = dynamic_cast<QSGSimpleTextureNode *>(node)) { return updateRenderableNode(QSGSoftwareRenderableNode::SimpleTexture, tn); + } else if (QSGNinePatchNode *nn = dynamic_cast<QSGNinePatchNode *>(node)) { + return updateRenderableNode(QSGSoftwareRenderableNode::NinePatch, nn); + } else if (QSGRectangleNode *rn = dynamic_cast<QSGRectangleNode *>(node)) { + return updateRenderableNode(QSGSoftwareRenderableNode::SimpleRectangle, rn); + } else if (QSGImageNode *n = dynamic_cast<QSGImageNode *>(node)) { + return updateRenderableNode(QSGSoftwareRenderableNode::SimpleImage, n); } else { // We dont know, so skip return false; @@ -122,12 +135,12 @@ void QSGSoftwareRenderableNodeUpdater::endVisit(QSGOpacityNode *) m_opacityState.pop(); } -bool QSGSoftwareRenderableNodeUpdater::visit(QSGImageNode *node) +bool QSGSoftwareRenderableNodeUpdater::visit(QSGInternalImageNode *node) { return updateRenderableNode(QSGSoftwareRenderableNode::Image, node); } -void QSGSoftwareRenderableNodeUpdater::endVisit(QSGImageNode *) +void QSGSoftwareRenderableNodeUpdater::endVisit(QSGInternalImageNode *) { } @@ -140,12 +153,12 @@ void QSGSoftwareRenderableNodeUpdater::endVisit(QSGPainterNode *) { } -bool QSGSoftwareRenderableNodeUpdater::visit(QSGRectangleNode *node) +bool QSGSoftwareRenderableNodeUpdater::visit(QSGInternalRectangleNode *node) { return updateRenderableNode(QSGSoftwareRenderableNode::Rectangle, node); } -void QSGSoftwareRenderableNodeUpdater::endVisit(QSGRectangleNode *) +void QSGSoftwareRenderableNodeUpdater::endVisit(QSGInternalRectangleNode *) { } @@ -158,22 +171,32 @@ void QSGSoftwareRenderableNodeUpdater::endVisit(QSGGlyphNode *) { } -bool QSGSoftwareRenderableNodeUpdater::visit(QSGNinePatchNode *node) +bool QSGSoftwareRenderableNodeUpdater::visit(QSGRootNode *node) { - return updateRenderableNode(QSGSoftwareRenderableNode::NinePatch, node); + m_stateMap[node] = currentState(node); + return true; } -void QSGSoftwareRenderableNodeUpdater::endVisit(QSGNinePatchNode *) +void QSGSoftwareRenderableNodeUpdater::endVisit(QSGRootNode *) { } -bool QSGSoftwareRenderableNodeUpdater::visit(QSGRootNode *node) +bool QSGSoftwareRenderableNodeUpdater::visit(QSGSpriteNode *node) { - m_stateMap[node] = currentState(node); - return true; + return updateRenderableNode(QSGSoftwareRenderableNode::SpriteNode, node); } -void QSGSoftwareRenderableNodeUpdater::endVisit(QSGRootNode *) +void QSGSoftwareRenderableNodeUpdater::endVisit(QSGSpriteNode *) +{ + +} + +bool QSGSoftwareRenderableNodeUpdater::visit(QSGRenderNode *node) +{ + return updateRenderableNode(QSGSoftwareRenderableNode::RenderNode, node); +} + +void QSGSoftwareRenderableNodeUpdater::endVisit(QSGRenderNode *) { } @@ -195,12 +218,13 @@ void QSGSoftwareRenderableNodeUpdater::updateNodes(QSGNode *node, bool isNodeRem m_opacityState.push(state.opacity); m_transformState.push(state.transform); m_clipState.push(state.clip); - + m_hasClip = state.hasClip; } else { // There is no parent, and no previous parent, so likely a root node m_opacityState.push(1.0f); m_transformState.push(QTransform()); m_clipState.push(QRegion()); + m_hasClip = false; } // If the node is being removed, then cleanup the state data @@ -256,6 +280,13 @@ void QSGSoftwareRenderableNodeUpdater::updateNodes(QSGNode *node, bool isNodeRem visitChildren(node); break; } + case QSGNode::RenderNodeType: { + QSGRenderNode *r = static_cast<QSGRenderNode*>(node); + if (visit(r)) + visitChildren(r); + endVisit(r); + break; + } default: Q_UNREACHABLE(); break; @@ -267,6 +298,7 @@ QSGSoftwareRenderableNodeUpdater::NodeState QSGSoftwareRenderableNodeUpdater::cu NodeState state; state.opacity = m_opacityState.top(); state.clip = m_clipState.top(); + state.hasClip = m_hasClip; state.transform = m_transformState.top(); state.parent = node->parent(); return state; diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater_p.h index 562d15769e..f204867236 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater_p.h @@ -76,18 +76,20 @@ public: void endVisit(QSGGeometryNode *) override; bool visit(QSGOpacityNode *) override; void endVisit(QSGOpacityNode *) override; - bool visit(QSGImageNode *) override; - void endVisit(QSGImageNode *) override; + bool visit(QSGInternalImageNode *) override; + void endVisit(QSGInternalImageNode *) override; bool visit(QSGPainterNode *) override; void endVisit(QSGPainterNode *) override; - bool visit(QSGRectangleNode *) override; - void endVisit(QSGRectangleNode *) override; + bool visit(QSGInternalRectangleNode *) override; + void endVisit(QSGInternalRectangleNode *) override; bool visit(QSGGlyphNode *) override; void endVisit(QSGGlyphNode *) override; - bool visit(QSGNinePatchNode *) override; - void endVisit(QSGNinePatchNode *) override; bool visit(QSGRootNode *) override; 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); @@ -95,6 +97,7 @@ private: struct NodeState { float opacity; QRegion clip; + bool hasClip; QTransform transform; QSGNode *parent; }; @@ -107,6 +110,7 @@ private: QSGAbstractSoftwareRenderer *m_renderer; QStack<float> m_opacityState; QStack<QRegion> m_clipState; + bool m_hasClip; QStack<QTransform> m_transformState; QHash<QSGNode*,NodeState> m_stateMap; }; @@ -124,7 +128,7 @@ bool QSGSoftwareRenderableNodeUpdater::updateRenderableNode(QSGSoftwareRenderabl //Update the node renderableNode->setTransform(m_transformState.top()); renderableNode->setOpacity(m_opacityState.top()); - renderableNode->setClipRegion(m_clipState.top()); + renderableNode->setClipRegion(m_clipState.top(), m_hasClip); renderableNode->update(); m_stateMap[node] = currentState(node); diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp index ea00de7a66..cad826fb27 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp @@ -45,6 +45,7 @@ #include "qsgsoftwarerenderablenode_p.h" #include <QtGui/QPaintDevice> +#include <QtGui/QBackingStore> #include <QElapsedTimer> Q_LOGGING_CATEGORY(lcRenderer, "qt.scenegraph.softwarecontext.renderer") @@ -53,6 +54,8 @@ QT_BEGIN_NAMESPACE QSGSoftwareRenderer::QSGSoftwareRenderer(QSGRenderContext *context) : QSGAbstractSoftwareRenderer(context) + , m_paintDevice(nullptr) + , m_backingStore(nullptr) { } @@ -63,6 +66,18 @@ QSGSoftwareRenderer::~QSGSoftwareRenderer() void QSGSoftwareRenderer::setCurrentPaintDevice(QPaintDevice *device) { m_paintDevice = device; + m_backingStore = nullptr; +} + +QPaintDevice *QSGSoftwareRenderer::currentPaintDevice() const +{ + return m_paintDevice; +} + +void QSGSoftwareRenderer::setBackingStore(QBackingStore *backingStore) +{ + m_backingStore = backingStore; + m_paintDevice = nullptr; } QRegion QSGSoftwareRenderer::flushRegion() const @@ -82,18 +97,24 @@ void QSGSoftwareRenderer::renderScene(uint) void QSGSoftwareRenderer::render() { - if (!m_paintDevice) + if (!m_paintDevice && !m_backingStore) return; + // If there is a backingstore, set the current paint device + if (m_backingStore) { + // For HiDPI QBackingStores, the paint device is not valid + // until begin() has been called. See: QTBUG-55875 + m_backingStore->beginPaint(QRegion()); + m_paintDevice = m_backingStore->paintDevice(); + m_backingStore->endPaint(); + } + QElapsedTimer renderTimer; setBackgroundColor(clearColor()); setBackgroundSize(QSize(m_paintDevice->width() / m_paintDevice->devicePixelRatio(), m_paintDevice->height() / m_paintDevice->devicePixelRatio())); - QPainter painter(m_paintDevice); - painter.setRenderHint(QPainter::Antialiasing); - // Build Renderlist // The renderlist is created by visiting each node in the tree and when a // renderable node is reach, we find the coorosponding RenderableNode object @@ -113,13 +134,31 @@ void QSGSoftwareRenderer::render() // side effect of this is that additional nodes may need to be marked dirty to // force a repaint. It is also important that any item that needs to be // repainted only paints what is needed, via the use of clip regions. - optimizeRenderList(); + const QRegion updateRegion = optimizeRenderList(); qint64 optimizeRenderListTime = renderTimer.restart(); + // If Rendering to a backingstore, prepare it to be updated + if (m_backingStore != nullptr) { + m_backingStore->beginPaint(updateRegion); + // It is possible that a QBackingStore's paintDevice() will change + // when begin() is called. + m_paintDevice = m_backingStore->paintDevice(); + } + + QPainter painter(m_paintDevice); + painter.setRenderHint(QPainter::Antialiasing); + auto rc = static_cast<QSGSoftwareRenderContext *>(context()); + QPainter *prevPainter = rc->m_activePainter; + rc->m_activePainter = &painter; + // Render the contents Renderlist m_flushRegion = renderNodes(&painter); qint64 renderTime = renderTimer.elapsed(); + 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/qsgsoftwarerenderer_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer_p.h index e2b8bcddca..bb28da4ca5 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer_p.h @@ -56,6 +56,7 @@ QT_BEGIN_NAMESPACE class QPaintDevice; +class QBackingStore; class Q_QUICK_PRIVATE_EXPORT QSGSoftwareRenderer : public QSGAbstractSoftwareRenderer { @@ -64,6 +65,8 @@ public: virtual ~QSGSoftwareRenderer(); void setCurrentPaintDevice(QPaintDevice *device); + QPaintDevice *currentPaintDevice() const; + void setBackingStore(QBackingStore *backingStore); QRegion flushRegion() const; protected: @@ -72,6 +75,7 @@ protected: private: QPaintDevice* m_paintDevice; + QBackingStore* m_backingStore; QRegion m_flushRegion; }; diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder.cpp index af81ff61c3..4e34517dad 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder.cpp @@ -41,15 +41,16 @@ #include "qsgsoftwarerenderablenode_p.h" #include "qsgabstractsoftwarerenderer_p.h" -#include "qsgsoftwareimagenode_p.h" -#include "qsgsoftwarerectanglenode_p.h" +#include "qsgsoftwareinternalimagenode_p.h" +#include "qsgsoftwareinternalrectanglenode_p.h" #include "qsgsoftwareglyphnode_p.h" -#include "qsgsoftwareninepatchnode_p.h" +#include "qsgsoftwarepublicnodes_p.h" #include "qsgsoftwarepainternode_p.h" #include "qsgsoftwarepixmaptexture_p.h" -#include <QtQuick/QSGSimpleRectNode> +#include <QtQuick/qsgsimplerectnode.h> #include <QtQuick/qsgsimpletexturenode.h> +#include <QtQuick/qsgrendernode.h> QT_BEGIN_NAMESPACE @@ -95,12 +96,12 @@ void QSGSoftwareRenderListBuilder::endVisit(QSGOpacityNode *) { } -bool QSGSoftwareRenderListBuilder::visit(QSGImageNode *node) +bool QSGSoftwareRenderListBuilder::visit(QSGInternalImageNode *node) { return addRenderableNode(node); } -void QSGSoftwareRenderListBuilder::endVisit(QSGImageNode *) +void QSGSoftwareRenderListBuilder::endVisit(QSGInternalImageNode *) { } @@ -113,12 +114,12 @@ void QSGSoftwareRenderListBuilder::endVisit(QSGPainterNode *) { } -bool QSGSoftwareRenderListBuilder::visit(QSGRectangleNode *node) +bool QSGSoftwareRenderListBuilder::visit(QSGInternalRectangleNode *node) { return addRenderableNode(node); } -void QSGSoftwareRenderListBuilder::endVisit(QSGRectangleNode *) +void QSGSoftwareRenderListBuilder::endVisit(QSGInternalRectangleNode *) { } @@ -131,21 +132,31 @@ void QSGSoftwareRenderListBuilder::endVisit(QSGGlyphNode *) { } -bool QSGSoftwareRenderListBuilder::visit(QSGNinePatchNode *node) +bool QSGSoftwareRenderListBuilder::visit(QSGRootNode *) +{ + return true; +} + +void QSGSoftwareRenderListBuilder::endVisit(QSGRootNode *) +{ +} + +bool QSGSoftwareRenderListBuilder::visit(QSGSpriteNode *node) { return addRenderableNode(node); } -void QSGSoftwareRenderListBuilder::endVisit(QSGNinePatchNode *) +void QSGSoftwareRenderListBuilder::endVisit(QSGSpriteNode *) { + } -bool QSGSoftwareRenderListBuilder::visit(QSGRootNode *) +bool QSGSoftwareRenderListBuilder::visit(QSGRenderNode *node) { - return true; + return addRenderableNode(node); } -void QSGSoftwareRenderListBuilder::endVisit(QSGRootNode *) +void QSGSoftwareRenderListBuilder::endVisit(QSGRenderNode *) { } diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder_p.h index 94b563564d..807cb7fdbe 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder_p.h @@ -70,18 +70,20 @@ public: void endVisit(QSGGeometryNode *) override; bool visit(QSGOpacityNode *) override; void endVisit(QSGOpacityNode *) override; - bool visit(QSGImageNode *) override; - void endVisit(QSGImageNode *) override; + bool visit(QSGInternalImageNode *) override; + void endVisit(QSGInternalImageNode *) override; bool visit(QSGPainterNode *) override; void endVisit(QSGPainterNode *) override; - bool visit(QSGRectangleNode *) override; - void endVisit(QSGRectangleNode *) override; + bool visit(QSGInternalRectangleNode *) override; + void endVisit(QSGInternalRectangleNode *) override; bool visit(QSGGlyphNode *) override; void endVisit(QSGGlyphNode *) override; - bool visit(QSGNinePatchNode *) override; - void endVisit(QSGNinePatchNode *) override; bool visit(QSGRootNode *) override; 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/adaptations/software/qsgsoftwarerenderloop.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp index 5292e1371f..19a963b403 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp @@ -156,11 +156,9 @@ void QSGSoftwareRenderLoop::renderWindow(QQuickWindow *window) //Tell the renderer about the windows backing store auto softwareRenderer = static_cast<QSGSoftwareRenderer*>(cd->renderer); if (softwareRenderer) - softwareRenderer->setCurrentPaintDevice(m_backingStores[window]->paintDevice()); + softwareRenderer->setBackingStore(m_backingStores[window]); - m_backingStores[window]->beginPaint(QRect(0, 0, window->width(), window->height())); cd->renderSceneGraph(window->size()); - m_backingStores[window]->endPaint(); if (profileFrames) renderTime = renderTimer.nsecsElapsed(); @@ -185,7 +183,7 @@ void QSGSoftwareRenderLoop::renderWindow(QQuickWindow *window) if (QSG_RASTER_LOG_TIME_RENDERLOOP().isDebugEnabled()) { static QTime lastFrameTime = QTime::currentTime(); qCDebug(QSG_RASTER_LOG_TIME_RENDERLOOP, - "Frame rendered with 'basic' renderloop in %dms, polish=%d, sync=%d, render=%d, swap=%d, frameDelta=%d", + "Frame rendered with 'software' renderloop in %dms, polish=%d, sync=%d, render=%d, swap=%d, frameDelta=%d", int(swapTime / 1000000), int(polishTime / 1000000), int((syncTime - polishTime) / 1000000), diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode.cpp new file mode 100644 index 0000000000..ba7bbc2d11 --- /dev/null +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode.cpp @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgsoftwarespritenode_p.h" +#include "qsgsoftwarepixmaptexture_p.h" +#include <QtGui/QPainter> + +QT_BEGIN_NAMESPACE + +QSGSoftwareSpriteNode::QSGSoftwareSpriteNode() +{ + setMaterial((QSGMaterial*)1); + setGeometry((QSGGeometry*)1); +} + +void QSGSoftwareSpriteNode::setTexture(QSGTexture *texture) +{ + m_texture = qobject_cast<QSGSoftwarePixmapTexture*>(texture); + markDirty(DirtyMaterial); +} + +void QSGSoftwareSpriteNode::setTime(float time) +{ + if (m_time != time) { + m_time = time; + markDirty(DirtyMaterial); + } +} + +void QSGSoftwareSpriteNode::setSourceA(const QPoint &source) +{ + if (m_sourceA != source) { + m_sourceA = source; + markDirty(DirtyMaterial); + } +} + +void QSGSoftwareSpriteNode::setSourceB(const QPoint &source) +{ + if (m_sourceB != source) { + m_sourceB = source; + markDirty(DirtyMaterial); + } +} + +void QSGSoftwareSpriteNode::setSpriteSize(const QSize &size) +{ + if (m_spriteSize != size) { + m_spriteSize = size; + markDirty(DirtyMaterial); + } +} + +void QSGSoftwareSpriteNode::setSheetSize(const QSize &size) +{ + if (m_sheetSize != size) { + m_sheetSize = size; + markDirty(DirtyMaterial); + } +} + +void QSGSoftwareSpriteNode::setSize(const QSizeF &size) +{ + if (m_size != size) { + m_size = size; + markDirty(DirtyGeometry); + } +} + +void QSGSoftwareSpriteNode::setFiltering(QSGTexture::Filtering filtering) +{ + Q_UNUSED(filtering); +} + +void QSGSoftwareSpriteNode::update() +{ +} + +void QSGSoftwareSpriteNode::paint(QPainter *painter) +{ + //Get the pixmap handle from the texture + if (!m_texture) + return; + + const QPixmap &pixmap = m_texture->pixmap(); + + // XXX try to do some kind of interpolation between sourceA and sourceB using time + painter->drawPixmap(QRectF(0, 0, m_size.width(), m_size.height()), + pixmap, + QRectF(m_sourceA, m_spriteSize)); +} + +bool QSGSoftwareSpriteNode::isOpaque() const +{ + return false; +} + +QRectF QSGSoftwareSpriteNode::rect() const +{ + return QRectF(0, 0, m_size.width(), m_size.height()); +} + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode_p.h new file mode 100644 index 0000000000..284ed3dff5 --- /dev/null +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode_p.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGSOFTWARESPRITENODE_H +#define QSGSOFTWARESPRITENODE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt 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. +// + +#include <private/qsgadaptationlayer_p.h> + +QT_BEGIN_NAMESPACE + +class QSGSoftwarePixmapTexture; +class QSGSoftwareSpriteNode : public QSGSpriteNode +{ +public: + QSGSoftwareSpriteNode(); + + void setTexture(QSGTexture *texture) override; + void setTime(float time) override; + void setSourceA(const QPoint &source) override; + void setSourceB(const QPoint &source) override; + void setSpriteSize(const QSize &size) override; + void setSheetSize(const QSize &size) override; + void setSize(const QSizeF &size) override; + void setFiltering(QSGTexture::Filtering filtering) override; + void update() override; + + void paint(QPainter *painter); + bool isOpaque() const; + QRectF rect() const; + +private: + + QSGSoftwarePixmapTexture *m_texture; + float m_time; + QPoint m_sourceA; + QPoint m_sourceB; + QSize m_spriteSize; + QSize m_sheetSize; + QSizeF m_size; + +}; + +QT_END_NAMESPACE + +#endif // QSGSOFTWARESPRITENODE_H diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp new file mode 100644 index 0000000000..5d5485ed8f --- /dev/null +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp @@ -0,0 +1,991 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgsoftwarethreadedrenderloop_p.h" +#include "qsgsoftwarecontext_p.h" +#include "qsgsoftwarerenderer_p.h" + +#include <private/qsgrenderer_p.h> +#include <private/qquickwindow_p.h> +#include <private/qquickprofiler_p.h> +#include <private/qquickanimatorcontroller_p.h> +#include <private/qquickprofiler_p.h> +#include <private/qqmldebugserviceinterfaces_p.h> +#include <private/qqmldebugconnector_p.h> + +#include <qpa/qplatformbackingstore.h> + +#include <QtCore/QQueue> +#include <QtCore/QElapsedTimer> +#include <QtCore/QThread> +#include <QtCore/QMutex> +#include <QtCore/QWaitCondition> +#include <QtGui/QGuiApplication> +#include <QtGui/QBackingStore> +#include <QtQuick/QQuickWindow> + +QT_BEGIN_NAMESPACE + +// Passed from the RL to the RT when a window is removed obscured and should be +// removed from the render loop. +const QEvent::Type WM_Obscure = QEvent::Type(QEvent::User + 1); + +// Passed from the RL to RT when GUI has been locked, waiting for sync. +const QEvent::Type WM_RequestSync = QEvent::Type(QEvent::User + 2); + +// Passed by the RT to itself to trigger another render pass. This is typically +// a result of QQuickWindow::update(). +const QEvent::Type WM_RequestRepaint = QEvent::Type(QEvent::User + 3); + +// Passed by the RL to the RT to maybe release resource if no windows are +// rendering. +const QEvent::Type WM_TryRelease = QEvent::Type(QEvent::User + 4); + +// Passed by the RL to the RT when a QQuickWindow::grabWindow() is called. +const QEvent::Type WM_Grab = QEvent::Type(QEvent::User + 5); + +// Passed by the window when there is a render job to run. +const QEvent::Type WM_PostJob = QEvent::Type(QEvent::User + 6); + +class QSGSoftwareWindowEvent : public QEvent +{ +public: + QSGSoftwareWindowEvent(QQuickWindow *c, QEvent::Type type) : QEvent(type), window(c) { } + QQuickWindow *window; +}; + +class QSGSoftwareTryReleaseEvent : public QSGSoftwareWindowEvent +{ +public: + QSGSoftwareTryReleaseEvent(QQuickWindow *win, bool destroy) + : QSGSoftwareWindowEvent(win, WM_TryRelease), destroying(destroy) { } + bool destroying; +}; + +class QSGSoftwareSyncEvent : public QSGSoftwareWindowEvent +{ +public: + QSGSoftwareSyncEvent(QQuickWindow *c, bool inExpose, bool force) + : QSGSoftwareWindowEvent(c, WM_RequestSync) + , size(c->size()) + , dpr(c->effectiveDevicePixelRatio()) + , syncInExpose(inExpose) + , forceRenderPass(force) { } + QSize size; + float dpr; + bool syncInExpose; + bool forceRenderPass; +}; + +class QSGSoftwareGrabEvent : public QSGSoftwareWindowEvent +{ +public: + QSGSoftwareGrabEvent(QQuickWindow *c, QImage *result) + : QSGSoftwareWindowEvent(c, WM_Grab), image(result) { } + QImage *image; +}; + +class QSGSoftwareJobEvent : public QSGSoftwareWindowEvent +{ +public: + QSGSoftwareJobEvent(QQuickWindow *c, QRunnable *postedJob) + : QSGSoftwareWindowEvent(c, WM_PostJob), job(postedJob) { } + ~QSGSoftwareJobEvent() { delete job; } + QRunnable *job; +}; + +class QSGSoftwareEventQueue : public QQueue<QEvent *> +{ +public: + void addEvent(QEvent *e) { + mutex.lock(); + enqueue(e); + if (waiting) + condition.wakeOne(); + mutex.unlock(); + } + + QEvent *takeEvent(bool wait) { + mutex.lock(); + if (isEmpty() && wait) { + waiting = true; + condition.wait(&mutex); + waiting = false; + } + QEvent *e = dequeue(); + mutex.unlock(); + return e; + } + + bool hasMoreEvents() { + mutex.lock(); + bool has = !isEmpty(); + mutex.unlock(); + return has; + } + +private: + QMutex mutex; + QWaitCondition condition; + bool waiting = false; +}; + +static inline int qsgrl_animation_interval() +{ + const qreal refreshRate = QGuiApplication::primaryScreen() ? QGuiApplication::primaryScreen()->refreshRate() : 0; + return refreshRate < 1 ? 16 : int(1000 / refreshRate); +} + +class QSGSoftwareRenderThread : public QThread +{ + Q_OBJECT +public: + QSGSoftwareRenderThread(QSGSoftwareThreadedRenderLoop *rl, QSGRenderContext *renderContext) + : renderLoop(rl) + { + rc = static_cast<QSGSoftwareRenderContext *>(renderContext); + vsyncDelta = qsgrl_animation_interval(); + } + + ~QSGSoftwareRenderThread() + { + delete rc; + } + + bool event(QEvent *e); + void run(); + + void syncAndRender(); + void sync(bool inExpose); + + void requestRepaint() + { + if (sleeping) + stopEventProcessing = true; + if (exposedWindow) + pendingUpdate |= RepaintRequest; + } + + void processEventsAndWaitForMore(); + void processEvents(); + void postEvent(QEvent *e); + + enum UpdateRequest { + SyncRequest = 0x01, + RepaintRequest = 0x02, + ExposeRequest = 0x04 | RepaintRequest | SyncRequest + }; + + QSGSoftwareThreadedRenderLoop *renderLoop; + QSGSoftwareRenderContext *rc; + QAnimationDriver *rtAnim = nullptr; + volatile bool active = false; + uint pendingUpdate = 0; + bool sleeping = false; + bool syncResultedInChanges = false; + float vsyncDelta; + QMutex mutex; + QWaitCondition waitCondition; + QQuickWindow *exposedWindow = nullptr; + QBackingStore *backingStore = nullptr; + bool stopEventProcessing = false; + QSGSoftwareEventQueue eventQueue; + QElapsedTimer renderThrottleTimer; + qint64 syncTime; + qint64 renderTime; + qint64 sinceLastTime; + +public slots: + void onSceneGraphChanged() { + syncResultedInChanges = true; + } +}; + +bool QSGSoftwareRenderThread::event(QEvent *e) +{ + switch ((int)e->type()) { + + case WM_Obscure: + Q_ASSERT(!exposedWindow || exposedWindow == static_cast<QSGSoftwareWindowEvent *>(e)->window); + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "RT - WM_Obscure" << exposedWindow; + mutex.lock(); + if (exposedWindow) { + QQuickWindowPrivate::get(exposedWindow)->fireAboutToStop(); + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_Obscure - window removed"); + exposedWindow = nullptr; + delete backingStore; + backingStore = nullptr; + } + waitCondition.wakeOne(); + mutex.unlock(); + return true; + + case WM_RequestSync: { + QSGSoftwareSyncEvent *wme = static_cast<QSGSoftwareSyncEvent *>(e); + if (sleeping) + stopEventProcessing = true; + exposedWindow = wme->window; + if (backingStore == nullptr) + backingStore = new QBackingStore(exposedWindow); + if (backingStore->size() != exposedWindow->size()) + backingStore->resize(exposedWindow->size()); + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "RT - WM_RequestSync" << exposedWindow; + pendingUpdate |= SyncRequest; + if (wme->syncInExpose) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_RequestSync - triggered from expose"); + pendingUpdate |= ExposeRequest; + } + if (wme->forceRenderPass) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_RequestSync - repaint regardless"); + pendingUpdate |= RepaintRequest; + } + return true; + } + + case WM_TryRelease: { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_TryRelease"); + mutex.lock(); + renderLoop->lockedForSync = true; + QSGSoftwareTryReleaseEvent *wme = static_cast<QSGSoftwareTryReleaseEvent *>(e); + // Only when no windows are exposed anymore or we are shutting down. + if (!exposedWindow || wme->destroying) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_TryRelease - invalidating rc"); + if (wme->window) { + QQuickWindowPrivate *wd = QQuickWindowPrivate::get(wme->window); + if (wme->destroying) { + // Bye bye nodes... + wd->cleanupNodesOnShutdown(); + } + rc->invalidate(); + QCoreApplication::processEvents(); + QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + if (wme->destroying) + delete wd->animationController; + } + if (wme->destroying) + active = false; + if (sleeping) + stopEventProcessing = true; + } else { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_TryRelease - not releasing because window is still active"); + } + waitCondition.wakeOne(); + renderLoop->lockedForSync = false; + mutex.unlock(); + return true; + } + + case WM_Grab: { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_Grab"); + QSGSoftwareGrabEvent *wme = static_cast<QSGSoftwareGrabEvent *>(e); + Q_ASSERT(wme->window); + Q_ASSERT(wme->window == exposedWindow || !exposedWindow); + mutex.lock(); + if (wme->window) { + // Grabbing is generally done by rendering a frame and reading the + // color buffer contents back, without presenting, and then + // creating a QImage from the returned data. It is terribly + // inefficient since it involves a full blocking wait for the GPU. + // However, our hands are tied by the existing, synchronous APIs of + // QQuickWindow and such. + QQuickWindowPrivate *wd = QQuickWindowPrivate::get(wme->window); + auto softwareRenderer = static_cast<QSGSoftwareRenderer*>(wd->renderer); + if (softwareRenderer) + softwareRenderer->setBackingStore(backingStore); + rc->initialize(nullptr); + wd->syncSceneGraph(); + wd->renderSceneGraph(wme->window->size()); + *wme->image = backingStore->handle()->toImage(); + } + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_Grab - waking gui to handle result"); + waitCondition.wakeOne(); + mutex.unlock(); + return true; + } + + case WM_PostJob: { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_PostJob"); + QSGSoftwareJobEvent *wme = static_cast<QSGSoftwareJobEvent *>(e); + Q_ASSERT(wme->window == exposedWindow); + if (exposedWindow) { + wme->job->run(); + delete wme->job; + wme->job = nullptr; + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_PostJob - job done"); + } + return true; + } + + case WM_RequestRepaint: + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_RequestPaint"); + // When GUI posts this event, it is followed by a polishAndSync, so we + // must not exit the event loop yet. + pendingUpdate |= RepaintRequest; + break; + + default: + break; + } + + return QThread::event(e); +} + +void QSGSoftwareRenderThread::postEvent(QEvent *e) +{ + eventQueue.addEvent(e); +} + +void QSGSoftwareRenderThread::processEvents() +{ + while (eventQueue.hasMoreEvents()) { + QEvent *e = eventQueue.takeEvent(false); + event(e); + delete e; + } +} + +void QSGSoftwareRenderThread::processEventsAndWaitForMore() +{ + stopEventProcessing = false; + while (!stopEventProcessing) { + QEvent *e = eventQueue.takeEvent(true); + event(e); + delete e; + } +} + +void QSGSoftwareRenderThread::run() +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - run()"); + + rtAnim = rc->sceneGraphContext()->createAnimationDriver(nullptr); + rtAnim->install(); + + if (QQmlDebugConnector::service<QQmlProfilerService>()) + QQuickProfiler::registerAnimationCallback(); + + renderThrottleTimer.start(); + + while (active) { + if (exposedWindow) + syncAndRender(); + + processEvents(); + QCoreApplication::processEvents(); + + if (pendingUpdate == 0 || !exposedWindow) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - done drawing, sleep"); + sleeping = true; + processEventsAndWaitForMore(); + sleeping = false; + } + } + + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - run() exiting"); + + delete rtAnim; + rtAnim = nullptr; + + rc->moveToThread(renderLoop->thread()); + moveToThread(renderLoop->thread()); +} + +void QSGSoftwareRenderThread::sync(bool inExpose) +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - sync"); + + mutex.lock(); + Q_ASSERT_X(renderLoop->lockedForSync, "QSGD3D12RenderThread::sync()", "sync triggered with gui not locked"); + + if (exposedWindow) { + QQuickWindowPrivate *wd = QQuickWindowPrivate::get(exposedWindow); + bool hadRenderer = wd->renderer != nullptr; + // If the scene graph was touched since the last sync() make sure it sends the + // changed signal. + if (wd->renderer) + wd->renderer->clearChangedFlag(); + + rc->initialize(nullptr); + wd->syncSceneGraph(); + + if (!hadRenderer && wd->renderer) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - created renderer"); + syncResultedInChanges = true; + connect(wd->renderer, &QSGRenderer::sceneGraphChanged, this, + &QSGSoftwareRenderThread::onSceneGraphChanged, Qt::DirectConnection); + } + + // Process deferred deletes now, directly after the sync as deleteLater + // on the GUI must now also have resulted in SG changes and the delete + // is a safe operation. + QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + } + + if (!inExpose) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - sync complete, waking gui"); + waitCondition.wakeOne(); + mutex.unlock(); + } +} + +void QSGSoftwareRenderThread::syncAndRender() +{ + Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphRenderLoopFrame); + + QElapsedTimer waitTimer; + waitTimer.start(); + + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - syncAndRender()"); + + syncResultedInChanges = false; + QQuickWindowPrivate *wd = QQuickWindowPrivate::get(exposedWindow); + + const bool repaintRequested = (pendingUpdate & RepaintRequest) || wd->customRenderStage; + const bool syncRequested = pendingUpdate & SyncRequest; + const bool exposeRequested = (pendingUpdate & ExposeRequest) == ExposeRequest; + pendingUpdate = 0; + + if (syncRequested) + sync(exposeRequested); + + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame); + + if (!syncResultedInChanges && !repaintRequested) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - no changes, render aborted"); + int waitTime = vsyncDelta - (int) waitTimer.elapsed(); + if (waitTime > 0) + msleep(waitTime); + return; + } + + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - rendering started"); + + if (rtAnim->isRunning()) { + wd->animationController->lock(); + rtAnim->advance(); + wd->animationController->unlock(); + } + + bool canRender = wd->renderer != nullptr; + + if (canRender) { + auto softwareRenderer = static_cast<QSGSoftwareRenderer*>(wd->renderer); + if (softwareRenderer) + softwareRenderer->setBackingStore(backingStore); + wd->renderSceneGraph(exposedWindow->size()); + + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame); + + if (softwareRenderer && (!wd->customRenderStage || !wd->customRenderStage->swap())) + backingStore->flush(softwareRenderer->flushRegion()); + + // Since there is no V-Sync with QBackingStore, throttle rendering the refresh + // rate of the current screen the window is on. + int blockTime = vsyncDelta - (int) renderThrottleTimer.elapsed(); + if (blockTime > 0) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "RT - blocking for " << blockTime << "ms"; + msleep(blockTime); + } + renderThrottleTimer.restart(); + + wd->fireFrameSwapped(); + } else { + Q_QUICK_SG_PROFILE_SKIP(QQuickProfiler::SceneGraphRenderLoopFrame, 1); + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - window not ready, skipping render"); + } + + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - rendering done"); + + if (exposeRequested) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - wake gui after initial expose"); + waitCondition.wakeOne(); + mutex.unlock(); + } + + Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRenderLoopFrame); +} + +template<class T> T *windowFor(const QVector<T> &list, QQuickWindow *window) +{ + for (const T &t : list) { + if (t.window == window) + return const_cast<T *>(&t); + } + return nullptr; +} + + +QSGSoftwareThreadedRenderLoop::QSGSoftwareThreadedRenderLoop() +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "software threaded render loop constructor"); + m_sg = new QSGSoftwareContext; + m_anim = m_sg->createAnimationDriver(this); + connect(m_anim, &QAnimationDriver::started, this, &QSGSoftwareThreadedRenderLoop::onAnimationStarted); + connect(m_anim, &QAnimationDriver::stopped, this, &QSGSoftwareThreadedRenderLoop::onAnimationStopped); + m_anim->install(); +} + +QSGSoftwareThreadedRenderLoop::~QSGSoftwareThreadedRenderLoop() +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "software threaded render loop destructor"); + delete m_sg; +} + +void QSGSoftwareThreadedRenderLoop::show(QQuickWindow *window) +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "show" << window; +} + +void QSGSoftwareThreadedRenderLoop::hide(QQuickWindow *window) +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "hide" << window; + + if (window->isExposed()) + handleObscurity(windowFor(m_windows, window)); + + releaseResources(window); +} + +void QSGSoftwareThreadedRenderLoop::resize(QQuickWindow *window) +{ + if (!window->isExposed() || window->size().isEmpty()) + return; + + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "resize" << window << window->size(); +} + +void QSGSoftwareThreadedRenderLoop::windowDestroyed(QQuickWindow *window) +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "window destroyed" << window; + + WindowData *w = windowFor(m_windows, window); + if (!w) + return; + + handleObscurity(w); + handleResourceRelease(w, true); + + QSGSoftwareRenderThread *thread = w->thread; + while (thread->isRunning()) + QThread::yieldCurrentThread(); + + Q_ASSERT(thread->thread() == QThread::currentThread()); + delete thread; + + for (int i = 0; i < m_windows.size(); ++i) { + if (m_windows.at(i).window == window) { + m_windows.removeAt(i); + break; + } + } +} + +void QSGSoftwareThreadedRenderLoop::exposureChanged(QQuickWindow *window) +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "exposure changed" << window; + + if (window->isExposed()) { + handleExposure(window); + } else { + WindowData *w = windowFor(m_windows, window); + if (w) + handleObscurity(w); + } +} + +QImage QSGSoftwareThreadedRenderLoop::grab(QQuickWindow *window) +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "grab" << window; + + WindowData *w = windowFor(m_windows, window); + // Have to support invisible (but created()'ed) windows as well. + // Unlike with GL, leaving that case for QQuickWindow to handle is not feasible. + const bool tempExpose = !w; + if (tempExpose) { + handleExposure(window); + w = windowFor(m_windows, window); + Q_ASSERT(w); + } + + if (!w->thread->isRunning()) + return QImage(); + + if (!window->handle()) + window->create(); + + QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window); + wd->polishItems(); + + QImage result; + w->thread->mutex.lock(); + lockedForSync = true; + w->thread->postEvent(new QSGSoftwareGrabEvent(window, &result)); + w->thread->waitCondition.wait(&w->thread->mutex); + lockedForSync = false; + w->thread->mutex.unlock(); + + result.setDevicePixelRatio(window->effectiveDevicePixelRatio()); + + if (tempExpose) + handleObscurity(w); + + return result; +} + +void QSGSoftwareThreadedRenderLoop::update(QQuickWindow *window) +{ + WindowData *w = windowFor(m_windows, window); + if (!w) + return; + + if (w->thread == QThread::currentThread()) { + w->thread->requestRepaint(); + return; + } + + // We set forceRenderPass because we want to make sure the QQuickWindow + // actually does a full render pass after the next sync. + w->forceRenderPass = true; + scheduleUpdate(w); +} + +void QSGSoftwareThreadedRenderLoop::maybeUpdate(QQuickWindow *window) +{ + WindowData *w = windowFor(m_windows, window); + if (w) + scheduleUpdate(w); +} + +void QSGSoftwareThreadedRenderLoop::handleUpdateRequest(QQuickWindow *window) +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "handleUpdateRequest" << window; + + WindowData *w = windowFor(m_windows, window); + if (w) + polishAndSync(w, false); +} + +QAnimationDriver *QSGSoftwareThreadedRenderLoop::animationDriver() const +{ + return m_anim; +} + +QSGContext *QSGSoftwareThreadedRenderLoop::sceneGraphContext() const +{ + return m_sg; +} + +QSGRenderContext *QSGSoftwareThreadedRenderLoop::createRenderContext(QSGContext *) const +{ + return m_sg->createRenderContext(); +} + +void QSGSoftwareThreadedRenderLoop::releaseResources(QQuickWindow *window) +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "releaseResources" << window; + + WindowData *w = windowFor(m_windows, window); + if (w) + handleResourceRelease(w, false); +} + +void QSGSoftwareThreadedRenderLoop::postJob(QQuickWindow *window, QRunnable *job) +{ + WindowData *w = windowFor(m_windows, window); + if (w && w->thread && w->thread->exposedWindow) + w->thread->postEvent(new QSGSoftwareJobEvent(window, job)); + else + delete job; +} + +QSurface::SurfaceType QSGSoftwareThreadedRenderLoop::windowSurfaceType() const +{ + return QSurface::RasterSurface; +} + +bool QSGSoftwareThreadedRenderLoop::interleaveIncubation() const +{ + bool somethingVisible = false; + for (const WindowData &w : m_windows) { + if (w.window->isVisible() && w.window->isExposed()) { + somethingVisible = true; + break; + } + } + return somethingVisible && m_anim->isRunning(); +} + +int QSGSoftwareThreadedRenderLoop::flags() const +{ + return SupportsGrabWithoutExpose; +} + +bool QSGSoftwareThreadedRenderLoop::event(QEvent *e) +{ + if (e->type() == QEvent::Timer) { + QTimerEvent *te = static_cast<QTimerEvent *>(e); + if (te->timerId() == animationTimer) { + m_anim->advance(); + emit timeToIncubate(); + return true; + } + } + + return QObject::event(e); +} + +void QSGSoftwareThreadedRenderLoop::onAnimationStarted() +{ + startOrStopAnimationTimer(); + + for (const WindowData &w : qAsConst(m_windows)) + w.window->requestUpdate(); +} + +void QSGSoftwareThreadedRenderLoop::onAnimationStopped() +{ + startOrStopAnimationTimer(); +} + +void QSGSoftwareThreadedRenderLoop::startOrStopAnimationTimer() +{ + int exposedWindowCount = 0; + const WindowData *exposed = nullptr; + + for (int i = 0; i < m_windows.size(); ++i) { + const WindowData &w(m_windows[i]); + if (w.window->isVisible() && w.window->isExposed()) { + ++exposedWindowCount; + exposed = &w; + } + } + + if (animationTimer && (exposedWindowCount == 1 || !m_anim->isRunning())) { + killTimer(animationTimer); + animationTimer = 0; + // If animations are running, make sure we keep on animating + if (m_anim->isRunning()) + exposed->window->requestUpdate(); + } else if (!animationTimer && exposedWindowCount != 1 && m_anim->isRunning()) { + animationTimer = startTimer(qsgrl_animation_interval()); + } +} + +void QSGSoftwareThreadedRenderLoop::handleExposure(QQuickWindow *window) +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "handleExposure" << window; + + WindowData *w = windowFor(m_windows, window); + if (!w) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "adding window to list"); + WindowData win; + win.window = window; + QSGRenderContext *rc = QQuickWindowPrivate::get(window)->context; // will transfer ownership + win.thread = new QSGSoftwareRenderThread(this, rc); + win.updateDuringSync = false; + win.forceRenderPass = true; // also covered by polishAndSync(inExpose=true), but doesn't hurt + m_windows.append(win); + w = &m_windows.last(); + } + + // set this early as we'll be rendering shortly anyway and this avoids + // special casing exposure in polishAndSync. + w->thread->exposedWindow = window; + + if (w->window->size().isEmpty() + || (w->window->isTopLevel() && !w->window->geometry().intersects(w->window->screen()->availableGeometry()))) { +#ifndef QT_NO_DEBUG + qWarning().noquote().nospace() << "QSGSotwareThreadedRenderLoop: expose event received for window " + << w->window << " with invalid geometry: " << w->window->geometry() + << " on " << w->window->screen(); +#endif + } + + if (!w->window->handle()) + w->window->create(); + + // Start render thread if it is not running + if (!w->thread->isRunning()) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "starting render thread"); + // Push a few things to the render thread. + QQuickAnimatorController *controller = QQuickWindowPrivate::get(w->window)->animationController; + if (controller->thread() != w->thread) + controller->moveToThread(w->thread); + if (w->thread->thread() == QThread::currentThread()) { + w->thread->rc->moveToThread(w->thread); + w->thread->moveToThread(w->thread); + } + + w->thread->active = true; + w->thread->start(); + + if (!w->thread->isRunning()) + qFatal("Render thread failed to start, aborting application."); + } + + polishAndSync(w, true); + + startOrStopAnimationTimer(); +} + +void QSGSoftwareThreadedRenderLoop::handleObscurity(QSGSoftwareThreadedRenderLoop::WindowData *w) +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "handleObscurity" << w->window; + + if (w->thread->isRunning()) { + w->thread->mutex.lock(); + w->thread->postEvent(new QSGSoftwareWindowEvent(w->window, WM_Obscure)); + w->thread->waitCondition.wait(&w->thread->mutex); + w->thread->mutex.unlock(); + } + + startOrStopAnimationTimer(); +} + +void QSGSoftwareThreadedRenderLoop::scheduleUpdate(QSGSoftwareThreadedRenderLoop::WindowData *w) +{ + if (!QCoreApplication::instance()) + return; + + if (!w || !w->thread->isRunning()) + return; + + QThread *current = QThread::currentThread(); + if (current != QCoreApplication::instance()->thread() && (current != w->thread || !lockedForSync)) { + qWarning() << "Updates can only be scheduled from GUI thread or from QQuickItem::updatePaintNode()"; + return; + } + + if (current == w->thread) { + w->updateDuringSync = true; + return; + } + + w->window->requestUpdate(); +} + +void QSGSoftwareThreadedRenderLoop::handleResourceRelease(QSGSoftwareThreadedRenderLoop::WindowData *w, bool destroying) +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "handleResourceRelease" << (destroying ? "destroying" : "hide/releaseResources") << w->window; + + w->thread->mutex.lock(); + if (w->thread->isRunning() && w->thread->active) { + QQuickWindow *window = w->window; + + // Note that window->handle() is typically null by this time because + // the platform window is already destroyed. This should not be a + // problem for the D3D cleanup. + + w->thread->postEvent(new QSGSoftwareTryReleaseEvent(window, destroying)); + w->thread->waitCondition.wait(&w->thread->mutex); + + // Avoid a shutdown race condition. + // If SG is invalidated and 'active' becomes false, the thread's run() + // method will exit. handleExposure() relies on QThread::isRunning() (because it + // potentially needs to start the thread again) and our mutex cannot be used to + // track the thread stopping, so we wait a few nanoseconds extra so the thread + // can exit properly. + if (!w->thread->active) + w->thread->wait(); + } + w->thread->mutex.unlock(); +} + +void QSGSoftwareThreadedRenderLoop::polishAndSync(QSGSoftwareThreadedRenderLoop::WindowData *w, bool inExpose) +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "polishAndSync" << (inExpose ? "(in expose)" : "(normal)") << w->window; + + QQuickWindow *window = w->window; + if (!w->thread || !w->thread->exposedWindow) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "polishAndSync - not exposed, abort"); + return; + } + + // Flush pending touch events. + QQuickWindowPrivate::get(window)->flushFrameSynchronousEvents(); + // The delivery of the event might have caused the window to stop rendering + w = windowFor(m_windows, window); + if (!w || !w->thread || !w->thread->exposedWindow) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "polishAndSync - removed after touch event flushing, abort"); + return; + } + + Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishAndSync); + + QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window); + wd->polishItems(); + + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync); + + w->updateDuringSync = false; + + emit window->afterAnimating(); + + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "polishAndSync - lock for sync"); + w->thread->mutex.lock(); + lockedForSync = true; + w->thread->postEvent(new QSGSoftwareSyncEvent(window, inExpose, w->forceRenderPass)); + w->forceRenderPass = false; + + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "polishAndSync - wait for sync"); + + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync); + w->thread->waitCondition.wait(&w->thread->mutex); + lockedForSync = false; + w->thread->mutex.unlock(); + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "polishAndSync - unlock after sync"); + + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync); + + if (!animationTimer && m_anim->isRunning()) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "polishAndSync - advancing animations"); + m_anim->advance(); + // We need to trigger another sync to keep animations running... + w->window->requestUpdate(); + emit timeToIncubate(); + } else if (w->updateDuringSync) { + w->window->requestUpdate(); + } + + Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphPolishAndSync); +} + +#include "qsgsoftwarethreadedrenderloop.moc" + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop_p.h new file mode 100644 index 0000000000..99993d651c --- /dev/null +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop_p.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGSOFTWARETHREADEDRENDERLOOP_H +#define QSGSOFTWARETHREADEDRENDERLOOP_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt 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. +// + +#include <private/qsgrenderloop_p.h> + +QT_BEGIN_NAMESPACE + +class QSGSoftwareRenderThread; +class QSGSoftwareContext; + +class QSGSoftwareThreadedRenderLoop : public QSGRenderLoop +{ + Q_OBJECT +public: + QSGSoftwareThreadedRenderLoop(); + ~QSGSoftwareThreadedRenderLoop(); + + void show(QQuickWindow *window) override; + void hide(QQuickWindow *window) override; + void resize(QQuickWindow *window) override; + void windowDestroyed(QQuickWindow *window) override; + void exposureChanged(QQuickWindow *window) override; + QImage grab(QQuickWindow *window) override; + void update(QQuickWindow *window) override; + void maybeUpdate(QQuickWindow *window) override; + void handleUpdateRequest(QQuickWindow *window) override; + QAnimationDriver *animationDriver() const override; + QSGContext *sceneGraphContext() const override; + QSGRenderContext *createRenderContext(QSGContext *) const override; + void releaseResources(QQuickWindow *window) override; + void postJob(QQuickWindow *window, QRunnable *job) override; + QSurface::SurfaceType windowSurfaceType() const override; + bool interleaveIncubation() const override; + int flags() const override; + + bool event(QEvent *e) override; + +public Q_SLOTS: + void onAnimationStarted(); + void onAnimationStopped(); + +private: + struct WindowData { + QQuickWindow *window; + QSGSoftwareRenderThread *thread; + uint updateDuringSync : 1; + uint forceRenderPass : 1; + }; + + void startOrStopAnimationTimer(); + void handleExposure(QQuickWindow *window); + void handleObscurity(WindowData *w); + void scheduleUpdate(WindowData *w); + void handleResourceRelease(WindowData *w, bool destroying); + void polishAndSync(WindowData *w, bool inExpose); + + QSGSoftwareContext *m_sg; + QAnimationDriver *m_anim; + int animationTimer = 0; + bool lockedForSync = false; + QVector<WindowData> m_windows; + + friend class QSGSoftwareRenderThread; +}; + +QT_END_NAMESPACE + +#endif // QSGSOFTWARETHREADEDRENDERLOOP_H diff --git a/src/quick/scenegraph/adaptations/software/software.pri b/src/quick/scenegraph/adaptations/software/software.pri index b8cdbc4a25..97644fc36a 100644 --- a/src/quick/scenegraph/adaptations/software/software.pri +++ b/src/quick/scenegraph/adaptations/software/software.pri @@ -6,10 +6,10 @@ SOURCES += \ $$PWD/qsgsoftwarecontext.cpp \ $$PWD/qsgabstractsoftwarerenderer.cpp \ $$PWD/qsgsoftwareglyphnode.cpp \ - $$PWD/qsgsoftwareimagenode.cpp \ - $$PWD/qsgsoftwareninepatchnode.cpp \ + $$PWD/qsgsoftwareinternalimagenode.cpp \ + $$PWD/qsgsoftwarepublicnodes.cpp \ $$PWD/qsgsoftwarepainternode.cpp \ - $$PWD/qsgsoftwarerectanglenode.cpp \ + $$PWD/qsgsoftwareinternalrectanglenode.cpp \ $$PWD/qsgsoftwarepixmaprenderer.cpp \ $$PWD/qsgsoftwarepixmaptexture.cpp \ $$PWD/qsgsoftwarerenderablenode.cpp \ @@ -18,22 +18,26 @@ SOURCES += \ $$PWD/qsgsoftwarerenderlistbuilder.cpp \ $$PWD/qsgsoftwarerenderloop.cpp \ $$PWD/qsgsoftwarelayer.cpp \ - $$PWD/qsgsoftwareadaptation.cpp + $$PWD/qsgsoftwareadaptation.cpp \ + $$PWD/qsgsoftwarespritenode.cpp \ + $$PWD/qsgsoftwarethreadedrenderloop.cpp HEADERS += \ $$PWD/qsgsoftwarecontext_p.h \ $$PWD/qsgabstractsoftwarerenderer_p.h \ $$PWD/qsgsoftwareglyphnode_p.h \ - $$PWD/qsgsoftwareimagenode_p.h \ - $$PWD/qsgsoftwareninepatchnode_p.h \ + $$PWD/qsgsoftwareinternalimagenode_p.h \ + $$PWD/qsgsoftwarepublicnodes_p.h \ $$PWD/qsgsoftwarepainternode_p.h \ $$PWD/qsgsoftwarepixmaprenderer_p.h \ $$PWD/qsgsoftwarepixmaptexture_p.h \ - $$PWD/qsgsoftwarerectanglenode_p.h \ + $$PWD/qsgsoftwareinternalrectanglenode_p.h \ $$PWD/qsgsoftwarerenderablenode_p.h \ $$PWD/qsgsoftwarerenderablenodeupdater_p.h \ $$PWD/qsgsoftwarerenderer_p.h \ $$PWD/qsgsoftwarerenderlistbuilder_p.h \ $$PWD/qsgsoftwarerenderloop_p.h \ $$PWD/qsgsoftwarelayer_p.h \ - $$PWD/qsgsoftwareadaptation_p.h + $$PWD/qsgsoftwareadaptation_p.h \ + $$PWD/qsgsoftwarespritenode_p.h \ + $$PWD/qsgsoftwarethreadedrenderloop_p.h diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index 9501b3bb3e..49bbbf0ba8 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -1033,11 +1033,13 @@ void Renderer::nodeWasAdded(QSGNode *node, Node *shadowParent) m_rebuild |= FullRebuild; } else if (node->type() == QSGNode::RenderNodeType) { - RenderNodeElement *e = new RenderNodeElement(static_cast<QSGRenderNode *>(node)); + QSGRenderNode *rn = static_cast<QSGRenderNode *>(node); + RenderNodeElement *e = new RenderNodeElement(rn); snode->data = e; - Q_ASSERT(!m_renderNodeElements.contains(static_cast<QSGRenderNode *>(node))); + Q_ASSERT(!m_renderNodeElements.contains(rn)); m_renderNodeElements.insert(e->renderNode, e); - m_useDepthBuffer = false; + if (!rn->flags().testFlag(QSGRenderNode::DepthAwareRendering)) + m_useDepthBuffer = false; m_rebuild |= FullRebuild; } @@ -2764,15 +2766,16 @@ void Renderer::render() struct RenderNodeState : public QSGRenderNode::RenderState { const QMatrix4x4 *projectionMatrix() const override { return m_projectionMatrix; } - QRect scissorRect() const { return m_scissorRect; } - bool scissorEnabled() const { return m_scissorEnabled; } - int stencilValue() const { return m_stencilValue; } - bool stencilEnabled() const { return m_stencilEnabled; } + QRect scissorRect() const override { return m_scissorRect; } + 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; - bool m_scissorEnabled; int m_stencilValue; + bool m_scissorEnabled; bool m_stencilEnabled; }; diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h index 01e517e65b..d5e94cea3e 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h @@ -499,7 +499,7 @@ public: void updateRootTransforms(Node *n); void updateRootTransforms(Node *n, Node *root, const QMatrix4x4 &combined); - void updateStates(QSGNode *n); + void updateStates(QSGNode *n) override; void visitNode(Node *n); void registerWithParentRoot(QSGNode *subRoot, QSGNode *parentRoot); diff --git a/src/quick/scenegraph/coreapi/qsggeometry.cpp b/src/quick/scenegraph/coreapi/qsggeometry.cpp index 7ec72a6e10..239557d527 100644 --- a/src/quick/scenegraph/coreapi/qsggeometry.cpp +++ b/src/quick/scenegraph/coreapi/qsggeometry.cpp @@ -726,6 +726,27 @@ void QSGGeometry::updateTexturedRectGeometry(QSGGeometry *g, const QRectF &rect, v[3].ty = textureRect.bottom(); } +/*! + Updates the geometry \a g with the coordinates in \a rect. + + The function assumes the geometry object contains a single triangle strip + of QSGGeometry::ColoredPoint2D vertices + */ +void QSGGeometry::updateColoredRectGeometry(QSGGeometry *g, const QRectF &rect) +{ + ColoredPoint2D *v = g->vertexDataAsColoredPoint2D(); + v[0].x = rect.left(); + v[0].y = rect.top(); + + v[1].x = rect.left(); + v[1].y = rect.bottom(); + + v[2].x = rect.right(); + v[2].y = rect.top(); + + v[3].x = rect.right(); + v[3].y = rect.bottom(); +} /*! diff --git a/src/quick/scenegraph/coreapi/qsggeometry.h b/src/quick/scenegraph/coreapi/qsggeometry.h index 1f54b7d81b..ae7b2f494c 100644 --- a/src/quick/scenegraph/coreapi/qsggeometry.h +++ b/src/quick/scenegraph/coreapi/qsggeometry.h @@ -182,6 +182,7 @@ public: static void updateRectGeometry(QSGGeometry *g, const QRectF &rect); static void updateTexturedRectGeometry(QSGGeometry *g, const QRectF &rect, const QRectF &sourceRect); + static void updateColoredRectGeometry(QSGGeometry *g, const QRectF &rect); void setIndexDataPattern(DataPattern p); DataPattern indexDataPattern() const { return DataPattern(m_index_usage_pattern); } diff --git a/src/quick/scenegraph/coreapi/qsgmaterial.cpp b/src/quick/scenegraph/coreapi/qsgmaterial.cpp index 42a4c4abd3..13598bbe1d 100644 --- a/src/quick/scenegraph/coreapi/qsgmaterial.cpp +++ b/src/quick/scenegraph/coreapi/qsgmaterial.cpp @@ -67,9 +67,9 @@ void qsg_set_material_failure() #ifndef QT_NO_OPENGL const char *QSGMaterialShaderPrivate::loadShaderSource(QOpenGLShader::ShaderType type) const { - QStringList files = m_sourceFiles[type]; + const QStringList files = m_sourceFiles[type]; QSGShaderSourceBuilder builder; - Q_FOREACH (const QString &file, files) + for (const QString &file : files) builder.appendSourceFile(file); m_sources[type] = builder.source(); return m_sources[type].constData(); @@ -681,7 +681,6 @@ QSGMaterial::~QSGMaterial() the full matrix of the geometry nodes for rendering. \value CustomCompileStep Starting with Qt 5.2, the scene graph will not always call - QSGMaterialShader::compile() when its shader program is compiled and linked. Set this flag to enforce that the function is called. diff --git a/src/quick/scenegraph/coreapi/qsgnode.cpp b/src/quick/scenegraph/coreapi/qsgnode.cpp index f5983fc00d..2211f88973 100644 --- a/src/quick/scenegraph/coreapi/qsgnode.cpp +++ b/src/quick/scenegraph/coreapi/qsgnode.cpp @@ -337,12 +337,12 @@ QSGNode::~QSGNode() to the scene graph and will cause the preprocess() function to be called for every frame the node is rendered. - The preprocess function is called before the update pass that propegates + The preprocess function is called before the update pass that propagates opacity and transformations through the scene graph. That means that functions like QSGOpacityNode::combinedOpacity() and QSGTransformNode::combinedMatrix() will not contain up-to-date values. If such values are changed during the preprocess, these changes will be - propegated through the scene graph before it is rendered. + propagated through the scene graph before it is rendered. \warning Beware of deleting nodes while they are being preprocessed. It is possible, with a small performance hit, to delete a single node during its @@ -1268,7 +1268,7 @@ QSGRootNode::QSGRootNode() QSGRootNode::~QSGRootNode() { while (!m_renderers.isEmpty()) - m_renderers.last()->setRootNode(0); + m_renderers.constLast()->setRootNode(0); destroy(); // Must call destroy() here because markDirty() casts this to QSGRootNode. } @@ -1349,7 +1349,7 @@ const qreal OPACITY_THRESHOLD = 0.001; Sets the opacity of this node to \a opacity. Before rendering the graph, the renderer will do an update pass - over the subtree to propegate the opacity to its children. + over the subtree to propagate the opacity to its children. The value will be bounded to the range 0 to 1. */ @@ -1466,8 +1466,6 @@ void QSGNodeVisitor::visitChildren(QSGNode *n) visitNode(c); } - - #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug d, const QSGGeometryNode *n) { diff --git a/src/quick/scenegraph/coreapi/qsgnode.h b/src/quick/scenegraph/coreapi/qsgnode.h index f7ea6dbe23..1467f2233d 100644 --- a/src/quick/scenegraph/coreapi/qsgnode.h +++ b/src/quick/scenegraph/coreapi/qsgnode.h @@ -325,7 +325,7 @@ public: void setCombinedOpacity(qreal opacity); qreal combinedOpacity() const { return m_combined_opacity; } - bool isSubtreeBlocked() const; + bool isSubtreeBlocked() const override; private: qreal m_opacity; diff --git a/src/quick/scenegraph/coreapi/qsgrenderer_p.h b/src/quick/scenegraph/coreapi/qsgrenderer_p.h index 94b78a85b4..3fb23fe3cd 100644 --- a/src/quick/scenegraph/coreapi/qsgrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgrenderer_p.h @@ -138,7 +138,7 @@ class QSGBindableFboId : public QSGBindable { public: QSGBindableFboId(GLuint); - virtual void bind() const; + void bind() const override; private: GLuint m_id; }; @@ -160,8 +160,8 @@ public: static void dump(QSGNode *n); QSGNodeDumper() : m_indent(0) {} - void visitNode(QSGNode *n); - void visitChildren(QSGNode *n); + void visitNode(QSGNode *n) override; + void visitChildren(QSGNode *n) override; private: int m_indent; diff --git a/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp b/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp index ffde9d8930..fa543aecad 100644 --- a/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp +++ b/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp @@ -54,12 +54,21 @@ QT_BEGIN_NAMESPACE necessary to query certain values, for instance the graphics device (e.g. the Direct3D or Vulkan device) that is used by the scenegraph. - \note QSGRendererInterface is only available after the scenegraph is - initialized. Additionally, there may be backend-specific limitations on - when the functions can be called. The only way that is guaranteed to - succeed is calling them when the rendering of a node (i.e. the preparation - of the command list for the next frame) is active. In practice this - typically means QSGRenderNode::render(). + QSGRendererInterface's functions have varying availability. API and + language queries, like graphicsApi() or shaderType() are always available, + meaning it is sufficient to construct a QQuickWindow or QQuickView, and the + graphics API or shading language in use can be queried right after via + QQuickWindow::rendererInterface(). This guarantees that utilities like the + GraphicsInfo QML type are able to report the correct values as early as + possible, without having conditional property values - depending on for + instance shaderType() - evaluate to unexpected values. + + Engine-specific accessors, like getResource(), are however available only + after the scenegraph is initialized. Additionally, there may be + backend-specific limitations on when such functions can be called. The only + way that is guaranteed to succeed is calling them when the rendering of a + node (i.e. the preparation of the command list for the next frame) is + active. In practice this typically means QSGRenderNode::render(). */ /*! @@ -68,15 +77,40 @@ QT_BEGIN_NAMESPACE \value Software The Qt Quick 2D Renderer is in use \value OpenGL OpenGL ES 2.0 or higher \value Direct3D12 Direct3D 12 - \value Vulkan Vulkan - \value Metal Metal */ /*! \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. + */ + +/*! + \enum QSGRendererInterface::ShaderType + \value UnknownShadingLanguage Not yet known due to no window and scenegraph associated + \value GLSL GLSL or GLSL ES + \value HLSL HLSL + */ + +/*! + \enum QSGRendererInterface::ShaderCompilationType + \value RuntimeCompilation Runtime compilation of shader source code is supported + \value OfflineCompilation Pre-compiled bytecode supported + */ + +/*! + \enum QSGRendererInterface::ShaderSourceType + + \value ShaderSourceString Shader source can be provided as a string in + the corresponding properties of ShaderEffect + + \value ShaderSourceFile Local or resource files containing shader source + code are supported + + \value ShaderByteCode Local or resource files containing shader bytecode are + supported */ QSGRendererInterface::~QSGRendererInterface() @@ -88,10 +122,7 @@ QSGRendererInterface::~QSGRendererInterface() Returns the graphics API that is in use by the Qt Quick scenegraph. - \note This function can be called on any thread. However, the renderer - interface's lifetime may be tied to the render thread and therefore calling - this function from other threads during the process of application shutdown - or QQuickWindow closing is likely to become invalid. + \note This function can be called on any thread. */ /*! @@ -104,10 +135,13 @@ QSGRendererInterface::~QSGRendererInterface() example, \c{VkDevice dev = *static_cast<VkDevice *>(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; } @@ -117,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; } @@ -131,10 +168,7 @@ void *QSGRendererInterface::getResource(const char *resource) const \return the shading language supported by the Qt Quick backend the application is using. - \note This function can be called on any thread. However, the renderer - interface's lifetime may be tied to the render thread and therefore calling - this function from other threads during the process of application shutdown - or QQuickWindow closing is likely to become invalid. + \note This function can be called on any thread. \sa QtQuick::GraphicsInfo */ @@ -145,10 +179,7 @@ void *QSGRendererInterface::getResource(const char *resource) const \return a bitmask of the shader compilation approaches supported by the Qt Quick backend the application is using. - \note This function can be called on any thread. However, the renderer - interface's lifetime may be tied to the render thread and therefore calling - this function from other threads during the process of application shutdown - or QQuickWindow closing is likely to become invalid. + \note This function can be called on any thread. \sa QtQuick::GraphicsInfo */ @@ -156,12 +187,9 @@ void *QSGRendererInterface::getResource(const char *resource) const /*! \fn QSGRendererInterface::ShaderSourceTypes QSGRendererInterface::shaderSourceType() const - \return a bitmask of the supported ways of providing shader sources. + \return a bitmask of the supported ways of providing shader sources in ShaderEffect items. - \note This function can be called on any thread. However, the renderer - interface's lifetime may be tied to the render thread and therefore calling - this function from other threads during the process of application shutdown - or QQuickWindow closing is likely to become invalid. + \note This function can be called on any thread. \sa QtQuick::GraphicsInfo */ 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 6c61b35aa1..5915d51f2b 100644 --- a/src/quick/scenegraph/coreapi/qsgrendernode.cpp +++ b/src/quick/scenegraph/coreapi/qsgrendernode.cpp @@ -44,7 +44,7 @@ QT_BEGIN_NAMESPACE /*! \class QSGRenderNode - \brief The QSGMaterialShader class represents a set of custom rendering commands + \brief The QSGRenderNode class represents a set of custom rendering commands targeting the graphics API that is in use by the scenegraph. \inmodule QtQuick \since 5.8 @@ -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 @@ -180,6 +179,11 @@ QSGRenderNode::StateFlags QSGRenderNode::changedStates() const default value according to the OpenGL specification. For other APIs, see the documentation for changedStates() for more information. + \note Depth writes are disabled when this function is called (for example, + glDepthMask(false) in case of OpenGL). Enabling depth writes can lead to + unexpected results, depending on the scenegraph backend in use, so nodes + should avoid this. + For APIs other than OpenGL, it will likely be necessary to query certain API-specific resources (for example, the graphics device or the command list/buffer to add the commands to). This is done via QSGRendererInterface. @@ -212,6 +216,68 @@ void QSGRenderNode::releaseResources() } /*! + \enum QSGRenderNode::RenderingFlag + + Possible values for the bitmask returned from flags(). + + \value BoundedRectRendering Indicates that the implementation of render() + does not render outside the area reported from rect() in item + coordinates. Such node implementations can lead to more efficient rendering, + depending on the scenegraph backend. For example, the software backend can + continue to use the more optimal partial update path when all render nodes + in the scene have this flag set. + + \value DepthAwareRendering Indicates that the implementations of render() + conforms to scenegraph expectations by only generating a Z value of 0 in + scene coordinates which is then transformed by the matrices retrieved from + RenderState::projectionMatrix() and matrix(), as described in the notes for + render(). Such node implementations can lead to more efficient rendering, + depending on the scenegraph backend. For example, the batching OpenGL + renderer can continue to use a more optimal path when all render nodes in + the scene have this flag set. + + \value OpaqueRendering Indicates that the implementation of render() writes + out opaque pixels for the entire area reported from rect(). By default the + renderers must assume that render() can also output semi or fully + transparent pixels. Setting this flag can improve performance in some + cases. + + \sa render(), rect() + */ + +/*! + \return flags describing the behavior of this render node. + + The default implementation returns 0. + + \sa RenderingFlag, rect() + */ +QSGRenderNode::RenderingFlags QSGRenderNode::flags() const +{ + return 0; +} + +/*! + \return the bounding rectangle in item coordinates for the area render() + touches. The value is only in use when flags() includes + BoundedRectRendering, ignored otherwise. + + Reporting the rectangle in combination with BoundedRectRendering is + particularly important with the \c software backend because otherwise + having a rendernode in the scene would trigger fullscreen updates, skipping + all partial update optimizations. + + For rendernodes covering the entire area of a corresponding QQuickItem the + return value will be (0, 0, item->width(), item->height()). + + \sa flags() +*/ +QRectF QSGRenderNode::rect() const +{ + return QRectF(); +} + +/*! \return pointer to the current model-view matrix. */ const QMatrix4x4 *QSGRenderNode::matrix() const @@ -287,6 +353,19 @@ QSGRenderNode::RenderState::~RenderState() */ /*! + \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. Reserved for future use. diff --git a/src/quick/scenegraph/coreapi/qsgrendernode.h b/src/quick/scenegraph/coreapi/qsgrendernode.h index 17569f8c59..f6bc40d3ee 100644 --- a/src/quick/scenegraph/coreapi/qsgrendernode.h +++ b/src/quick/scenegraph/coreapi/qsgrendernode.h @@ -61,6 +61,13 @@ public: }; Q_DECLARE_FLAGS(StateFlags, StateFlag) + enum RenderingFlag { + BoundedRectRendering = 0x01, + DepthAwareRendering = 0x02, + OpaqueRendering = 0x04 + }; + Q_DECLARE_FLAGS(RenderingFlags, RenderingFlag) + struct Q_QUICK_EXPORT RenderState { virtual ~RenderState(); virtual const QMatrix4x4 *projectionMatrix() const = 0; @@ -68,6 +75,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; }; @@ -77,6 +85,8 @@ public: virtual StateFlags changedStates() const; virtual void render(const RenderState *state) = 0; virtual void releaseResources(); + virtual RenderingFlags flags() const; + virtual QRectF rect() const; const QMatrix4x4 *matrix() const; const QSGClipNode *clipList() const; @@ -88,6 +98,7 @@ private: }; Q_DECLARE_OPERATORS_FOR_FLAGS(QSGRenderNode::StateFlags) +Q_DECLARE_OPERATORS_FOR_FLAGS(QSGRenderNode::RenderingFlags) QT_END_NAMESPACE diff --git a/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp b/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp index 3a35632d5c..48ab1aa52f 100644 --- a/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp +++ b/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp @@ -193,13 +193,13 @@ QByteArray qsgShaderRewriter_insertZAttributes(const char *input, QSurfaceFormat switch (profile) { case QSurfaceFormat::NoProfile: case QSurfaceFormat::CompatibilityProfile: - result += QByteArrayLiteral("attribute highp float _qt_order;\n"); - result += QByteArrayLiteral("uniform highp float _qt_zRange;\n"); + result += "attribute highp float _qt_order;\n" + "uniform highp float _qt_zRange;\n"; break; case QSurfaceFormat::CoreProfile: - result += QByteArrayLiteral("in float _qt_order;\n"); - result += QByteArrayLiteral("uniform float _qt_zRange;\n"); + result += "in float _qt_order;\n" + "uniform float _qt_zRange;\n"; break; } @@ -214,9 +214,9 @@ QByteArray qsgShaderRewriter_insertZAttributes(const char *input, QSurfaceFormat case Tokenizer::Token_CloseBrace: braceDepth--; if (braceDepth == 0) { - result += QByteArray::fromRawData(voidPos, tok.pos - 1 - voidPos); - result += QByteArrayLiteral(" gl_Position.z = (gl_Position.z * _qt_zRange + _qt_order) * gl_Position.w;\n"); - result += QByteArray(tok.pos - 1); + result += QByteArray::fromRawData(voidPos, tok.pos - 1 - voidPos) + + " gl_Position.z = (gl_Position.z * _qt_zRange + _qt_order) * gl_Position.w;\n" + + QByteArray(tok.pos - 1); return result; } break; diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp index 50986e2528..e219ddd82e 100644 --- a/src/quick/scenegraph/qsgadaptationlayer.cpp +++ b/src/quick/scenegraph/qsgadaptationlayer.cpp @@ -46,6 +46,7 @@ #include <private/qrawfont_p.h> #include <QtGui/qguiapplication.h> #include <qdir.h> +#include <qsgrendernode.h> #include <private/qquickprofiler_p.h> #include <QElapsedTimer> @@ -195,7 +196,7 @@ void QSGDistanceFieldGlyphCache::update() storeGlyphs(distanceFields); #if defined(QSG_DISTANCEFIELD_CACHE_DEBUG) - foreach (Texture texture, m_textures) + for (Texture texture : qAsConst(m_textures)) saveTexture(texture.textureId, texture.size.width(), texture.size.height()); #endif @@ -512,6 +513,13 @@ void QSGNodeVisitorEx::visitChildren(QSGNode *node) visitChildren(child); break; } + case QSGNode::RenderNodeType: { + QSGRenderNode *r = static_cast<QSGRenderNode*>(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 8fdcf7af64..a74b38dba8 100644 --- a/src/quick/scenegraph/qsgadaptationlayer_p.h +++ b/src/quick/scenegraph/qsgadaptationlayer_p.h @@ -76,12 +76,13 @@ class TextureReference; class QSGDistanceFieldGlyphCacheManager; class QSGDistanceFieldGlyphNode; class QOpenGLContext; -class QSGImageNode; +class QSGInternalImageNode; class QSGPainterNode; -class QSGRectangleNode; +class QSGInternalRectangleNode; class QSGGlyphNode; -class QSGNinePatchNode; class QSGRootNode; +class QSGSpriteNode; +class QSGRenderNode; class Q_QUICK_PRIVATE_EXPORT QSGNodeVisitorEx { @@ -97,18 +98,20 @@ public: virtual void endVisit(QSGGeometryNode *) = 0; virtual bool visit(QSGOpacityNode *) = 0; virtual void endVisit(QSGOpacityNode *) = 0; - virtual bool visit(QSGImageNode *) = 0; - virtual void endVisit(QSGImageNode *) = 0; + virtual bool visit(QSGInternalImageNode *) = 0; + virtual void endVisit(QSGInternalImageNode *) = 0; virtual bool visit(QSGPainterNode *) = 0; virtual void endVisit(QSGPainterNode *) = 0; - virtual bool visit(QSGRectangleNode *) = 0; - virtual void endVisit(QSGRectangleNode *) = 0; + virtual bool visit(QSGInternalRectangleNode *) = 0; + virtual void endVisit(QSGInternalRectangleNode *) = 0; virtual bool visit(QSGGlyphNode *) = 0; virtual void endVisit(QSGGlyphNode *) = 0; - virtual bool visit(QSGNinePatchNode *) = 0; - virtual void endVisit(QSGNinePatchNode *) = 0; virtual bool visit(QSGRootNode *) = 0; 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); }; @@ -122,7 +125,7 @@ public: virtual void accept(QSGNodeVisitorEx *) = 0; }; -class Q_QUICK_PRIVATE_EXPORT QSGRectangleNode : public QSGVisitableNode +class Q_QUICK_PRIVATE_EXPORT QSGInternalRectangleNode : public QSGVisitableNode { public: virtual void setRect(const QRectF &rect) = 0; @@ -140,7 +143,7 @@ public: }; -class Q_QUICK_PRIVATE_EXPORT QSGImageNode : public QSGVisitableNode +class Q_QUICK_PRIVATE_EXPORT QSGInternalImageNode : public QSGVisitableNode { public: virtual void setTargetRect(const QRectF &rect) = 0; @@ -186,19 +189,6 @@ public: virtual void accept(QSGNodeVisitorEx *visitor) { if (visitor->visit(this)) visitor->visitChildren(this); visitor->endVisit(this); } }; -class Q_QUICK_PRIVATE_EXPORT QSGNinePatchNode : public QSGVisitableNode -{ -public: - virtual void setTexture(QSGTexture *texture) = 0; - virtual void setBounds(const QRectF &bounds) = 0; - virtual void setDevicePixelRatio(qreal ratio) = 0; - virtual void setPadding(qreal left, qreal top, qreal right, qreal bottom) = 0; - - virtual void update() = 0; - - virtual void accept(QSGNodeVisitorEx *visitor) { if (visitor->visit(this)) visitor->visitChildren(this); visitor->endVisit(this); } -}; - class Q_QUICK_EXPORT QSGLayer : public QSGDynamicTexture { Q_OBJECT @@ -223,6 +213,23 @@ Q_SIGNALS: void scheduledUpdateCompleted(); }; +class Q_QUICK_PRIVATE_EXPORT QSGSpriteNode : public QSGVisitableNode +{ +public: + virtual void setTexture(QSGTexture *texture) = 0; + virtual void setTime(float time) = 0; + virtual void setSourceA(const QPoint &source) = 0; + virtual void setSourceB(const QPoint &source) = 0; + virtual void setSpriteSize(const QSize &size) = 0; + virtual void setSheetSize(const QSize &size) = 0; + virtual void setSize(const QSizeF &size) = 0; + virtual void setFiltering(QSGTexture::Filtering filtering) = 0; + + virtual void update() = 0; + + virtual void accept(QSGNodeVisitorEx *visitor) { if (visitor->visit(this)) visitor->visitChildren(this); visitor->endVisit(this); } +}; + class Q_QUICK_PRIVATE_EXPORT QSGGuiThreadShaderEffectManager : public QObject { Q_OBJECT @@ -273,9 +280,10 @@ public: uint constantDataSize; }; - virtual bool reflect(const QByteArray &src, ShaderInfo *result) = 0; + virtual void prepareShaderCode(ShaderInfo::Type typeHint, const QByteArray &src, ShaderInfo *result) = 0; Q_SIGNALS: + void shaderCodePrepared(bool ok, ShaderInfo::Type typeHint, const QByteArray &src, ShaderInfo *result); void textureChanged(); void logAndStatusChanged(); }; @@ -536,7 +544,8 @@ inline bool QSGDistanceFieldGlyphCache::containsGlyph(glyph_t glyph) return glyphData(glyph).texCoord.isValid(); } - QT_END_NAMESPACE +Q_DECLARE_METATYPE(QSGGuiThreadShaderEffectManager::ShaderInfo::Type) + #endif diff --git a/src/quick/scenegraph/qsgbasicimagenode.cpp b/src/quick/scenegraph/qsgbasicinternalimagenode.cpp index 24077cc947..685a51550d 100644 --- a/src/quick/scenegraph/qsgbasicimagenode.cpp +++ b/src/quick/scenegraph/qsgbasicinternalimagenode.cpp @@ -37,7 +37,7 @@ ** ****************************************************************************/ -#include "qsgbasicimagenode_p.h" +#include "qsgbasicinternalimagenode_p.h" #include <QtCore/qvarlengtharray.h> #include <QtCore/qmath.h> @@ -65,7 +65,7 @@ namespace } } -QSGBasicImageNode::QSGBasicImageNode() +QSGBasicInternalImageNode::QSGBasicInternalImageNode() : m_innerSourceRect(0, 0, 1, 1) , m_subSourceRect(0, 0, 1, 1) , m_antialiasing(false) @@ -77,11 +77,11 @@ QSGBasicImageNode::QSGBasicImageNode() setGeometry(&m_geometry); #ifdef QSG_RUNTIME_DESCRIPTION - qsgnode_set_description(this, QLatin1String("image")); + qsgnode_set_description(this, QLatin1String("internalimage")); #endif } -void QSGBasicImageNode::setTargetRect(const QRectF &rect) +void QSGBasicInternalImageNode::setTargetRect(const QRectF &rect) { if (rect == m_targetRect) return; @@ -89,7 +89,7 @@ void QSGBasicImageNode::setTargetRect(const QRectF &rect) m_dirtyGeometry = true; } -void QSGBasicImageNode::setInnerTargetRect(const QRectF &rect) +void QSGBasicInternalImageNode::setInnerTargetRect(const QRectF &rect) { if (rect == m_innerTargetRect) return; @@ -97,7 +97,7 @@ void QSGBasicImageNode::setInnerTargetRect(const QRectF &rect) m_dirtyGeometry = true; } -void QSGBasicImageNode::setInnerSourceRect(const QRectF &rect) +void QSGBasicInternalImageNode::setInnerSourceRect(const QRectF &rect) { if (rect == m_innerSourceRect) return; @@ -105,7 +105,7 @@ void QSGBasicImageNode::setInnerSourceRect(const QRectF &rect) m_dirtyGeometry = true; } -void QSGBasicImageNode::setSubSourceRect(const QRectF &rect) +void QSGBasicInternalImageNode::setSubSourceRect(const QRectF &rect) { if (rect == m_subSourceRect) return; @@ -113,7 +113,7 @@ void QSGBasicImageNode::setSubSourceRect(const QRectF &rect) m_dirtyGeometry = true; } -void QSGBasicImageNode::setTexture(QSGTexture *texture) +void QSGBasicInternalImageNode::setTexture(QSGTexture *texture) { Q_ASSERT(texture); @@ -126,7 +126,7 @@ void QSGBasicImageNode::setTexture(QSGTexture *texture) m_dirtyGeometry = true; } -void QSGBasicImageNode::setAntialiasing(bool antialiasing) +void QSGBasicInternalImageNode::setAntialiasing(bool antialiasing) { if (antialiasing == m_antialiasing) return; @@ -142,7 +142,7 @@ void QSGBasicImageNode::setAntialiasing(bool antialiasing) m_dirtyGeometry = true; } -void QSGBasicImageNode::setMirror(bool mirror) +void QSGBasicInternalImageNode::setMirror(bool mirror) { if (mirror == m_mirror) return; @@ -151,13 +151,13 @@ void QSGBasicImageNode::setMirror(bool mirror) } -void QSGBasicImageNode::update() +void QSGBasicInternalImageNode::update() { if (m_dirtyGeometry) updateGeometry(); } -void QSGBasicImageNode::preprocess() +void QSGBasicInternalImageNode::preprocess() { bool doDirty = false; QSGDynamicTexture *t = qobject_cast<QSGDynamicTexture *>(materialTexture()); @@ -200,7 +200,7 @@ static inline void appendQuad(quint16 **indices, quint16 topLeft, quint16 topRig *(*indices)++ = topLeft; } -QSGGeometry *QSGBasicImageNode::updateGeometry(const QRectF &targetRect, +QSGGeometry *QSGBasicInternalImageNode::updateGeometry(const QRectF &targetRect, const QRectF &innerTargetRect, const QRectF &sourceRect, const QRectF &innerSourceRect, @@ -458,7 +458,7 @@ QSGGeometry *QSGBasicImageNode::updateGeometry(const QRectF &targetRect, return geometry; } -void QSGBasicImageNode::updateGeometry() +void QSGBasicInternalImageNode::updateGeometry() { Q_ASSERT(!m_targetRect.isEmpty()); const QSGTexture *t = materialTexture(); diff --git a/src/quick/scenegraph/qsgbasicimagenode_p.h b/src/quick/scenegraph/qsgbasicinternalimagenode_p.h index 4a96e1a9f6..a5689b20aa 100644 --- a/src/quick/scenegraph/qsgbasicimagenode_p.h +++ b/src/quick/scenegraph/qsgbasicinternalimagenode_p.h @@ -37,8 +37,8 @@ ** ****************************************************************************/ -#ifndef QSGBASICIMAGENODE_P_H -#define QSGBASICIMAGENODE_P_H +#ifndef QSGBASICINTERNALIMAGENODE_P_H +#define QSGBASICINTERNALIMAGENODE_P_H // // W A R N I N G @@ -55,10 +55,10 @@ QT_BEGIN_NAMESPACE -class Q_QUICK_PRIVATE_EXPORT QSGBasicImageNode : public QSGImageNode +class Q_QUICK_PRIVATE_EXPORT QSGBasicInternalImageNode : public QSGInternalImageNode { public: - QSGBasicImageNode(); + QSGBasicInternalImageNode(); void setTargetRect(const QRectF &rect) override; void setInnerTargetRect(const QRectF &rect) override; diff --git a/src/quick/scenegraph/qsgbasicrectanglenode.cpp b/src/quick/scenegraph/qsgbasicinternalrectanglenode.cpp index 14d2dc9677..8fc850b60c 100644 --- a/src/quick/scenegraph/qsgbasicrectanglenode.cpp +++ b/src/quick/scenegraph/qsgbasicinternalrectanglenode.cpp @@ -37,7 +37,7 @@ ** ****************************************************************************/ -#include "qsgbasicrectanglenode_p.h" +#include "qsgbasicinternalrectanglenode_p.h" #include <QtCore/qmath.h> @@ -96,7 +96,7 @@ namespace } } -QSGBasicRectangleNode::QSGBasicRectangleNode() +QSGBasicInternalRectangleNode::QSGBasicInternalRectangleNode() : m_radius(0) , m_pen_width(0) , m_aligned(true) @@ -108,11 +108,11 @@ QSGBasicRectangleNode::QSGBasicRectangleNode() setGeometry(&m_geometry); #ifdef QSG_RUNTIME_DESCRIPTION - qsgnode_set_description(this, QLatin1String("rectangle")); + qsgnode_set_description(this, QLatin1String("internalrectangle")); #endif } -void QSGBasicRectangleNode::setRect(const QRectF &rect) +void QSGBasicInternalRectangleNode::setRect(const QRectF &rect) { if (rect == m_rect) return; @@ -120,7 +120,7 @@ void QSGBasicRectangleNode::setRect(const QRectF &rect) m_dirty_geometry = true; } -void QSGBasicRectangleNode::setColor(const QColor &color) +void QSGBasicInternalRectangleNode::setColor(const QColor &color) { if (color == m_color) return; @@ -129,7 +129,7 @@ void QSGBasicRectangleNode::setColor(const QColor &color) m_dirty_geometry = true; } -void QSGBasicRectangleNode::setPenColor(const QColor &color) +void QSGBasicInternalRectangleNode::setPenColor(const QColor &color) { if (color == m_border_color) return; @@ -138,7 +138,7 @@ void QSGBasicRectangleNode::setPenColor(const QColor &color) m_dirty_geometry = true; } -void QSGBasicRectangleNode::setPenWidth(qreal width) +void QSGBasicInternalRectangleNode::setPenWidth(qreal width) { if (width == m_pen_width) return; @@ -147,7 +147,7 @@ void QSGBasicRectangleNode::setPenWidth(qreal width) } -void QSGBasicRectangleNode::setGradientStops(const QGradientStops &stops) +void QSGBasicInternalRectangleNode::setGradientStops(const QGradientStops &stops) { if (stops.constData() == m_gradient_stops.constData()) return; @@ -160,7 +160,7 @@ void QSGBasicRectangleNode::setGradientStops(const QGradientStops &stops) m_dirty_geometry = true; } -void QSGBasicRectangleNode::setRadius(qreal radius) +void QSGBasicInternalRectangleNode::setRadius(qreal radius) { if (radius == m_radius) return; @@ -168,7 +168,7 @@ void QSGBasicRectangleNode::setRadius(qreal radius) m_dirty_geometry = true; } -void QSGBasicRectangleNode::setAntialiasing(bool antialiasing) +void QSGBasicInternalRectangleNode::setAntialiasing(bool antialiasing) { if (!supportsAntialiasing()) return; @@ -187,7 +187,7 @@ void QSGBasicRectangleNode::setAntialiasing(bool antialiasing) m_dirty_geometry = true; } -void QSGBasicRectangleNode::setAligned(bool aligned) +void QSGBasicInternalRectangleNode::setAligned(bool aligned) { if (aligned == m_aligned) return; @@ -195,7 +195,7 @@ void QSGBasicRectangleNode::setAligned(bool aligned) m_dirty_geometry = true; } -void QSGBasicRectangleNode::update() +void QSGBasicInternalRectangleNode::update() { if (m_dirty_geometry) { updateGeometry(); @@ -207,7 +207,7 @@ void QSGBasicRectangleNode::update() } } -void QSGBasicRectangleNode::updateGeometry() +void QSGBasicInternalRectangleNode::updateGeometry() { float width = float(m_rect.width()); float height = float(m_rect.height()); diff --git a/src/quick/scenegraph/qsgbasicrectanglenode_p.h b/src/quick/scenegraph/qsgbasicinternalrectanglenode_p.h index b1d1457590..98e53669ce 100644 --- a/src/quick/scenegraph/qsgbasicrectanglenode_p.h +++ b/src/quick/scenegraph/qsgbasicinternalrectanglenode_p.h @@ -38,8 +38,8 @@ ****************************************************************************/ -#ifndef QSGBASICRECTANGLENODE_P_H -#define QSGBASICRECTANGLENODE_P_H +#ifndef QSGBASICINTERNALRECTANGLENODE_P_H +#define QSGBASICINTERNALRECTANGLENODE_P_H // // W A R N I N G @@ -56,10 +56,10 @@ QT_BEGIN_NAMESPACE -class Q_QUICK_PRIVATE_EXPORT QSGBasicRectangleNode : public QSGRectangleNode +class Q_QUICK_PRIVATE_EXPORT QSGBasicInternalRectangleNode : public QSGInternalRectangleNode { public: - QSGBasicRectangleNode(); + QSGBasicInternalRectangleNode(); void setRect(const QRectF &rect) override; void setColor(const QColor &color) override; diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index 40d65d99aa..688fc7db08 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -76,7 +76,7 @@ QT_BEGIN_NAMESPACE // Used for very high-level info about the renderering and gl context // Includes GL_VERSION, type of render loop, atlas size, etc. -Q_LOGGING_CATEGORY(QSG_LOG_INFO, "qt.scenegraph.info") +Q_LOGGING_CATEGORY(QSG_LOG_INFO, "qt.scenegraph.general") // Used to debug the renderloop logic. Primarily useful for platform integrators // and when investigating the render loop logic. @@ -268,9 +268,9 @@ void QSGContext::renderContextInvalidated(QSGRenderContext *) /*! Convenience factory function for creating a colored rectangle with the given geometry. */ -QSGRectangleNode *QSGContext::createRectangleNode(const QRectF &rect, const QColor &c) +QSGInternalRectangleNode *QSGContext::createInternalRectangleNode(const QRectF &rect, const QColor &c) { - QSGRectangleNode *node = createRectangleNode(); + QSGInternalRectangleNode *node = createInternalRectangleNode(); node->setRect(rect); node->setColor(c); node->update(); @@ -318,7 +318,15 @@ QSize QSGContext::minimumFBOSize() const Returns a pointer to the (presumably) global renderer interface. \note This function may be called on the gui thread in order to get access - to QSGRendererInterface::graphicsApi(). + to QSGRendererInterface::graphicsApi() and other getters. + + \note it is expected that the simple queries (graphicsApi, shaderType, + etc.) are available regardless of the render context validity (i.e. + scenegraph status). This does not apply to engine-specific getters like + getResource(). In the end this means that this function must always return + a valid object in subclasses, even when renderContext->isValid() is false. + The typical pattern is to implement the QSGRendererInterface in the + QSGContext or QSGRenderContext subclass itself, whichever is more suitable. */ QSGRendererInterface *QSGContext::rendererInterface(QSGRenderContext *renderContext) { @@ -335,7 +343,6 @@ QSGRenderContext::QSGRenderContext(QSGContext *context) QSGRenderContext::~QSGRenderContext() { - invalidate(); } void QSGRenderContext::initialize(void *context) @@ -345,8 +352,6 @@ void QSGRenderContext::initialize(void *context) void QSGRenderContext::invalidate() { - m_sg->renderContextInvalidated(this); - emit invalidated(); } void QSGRenderContext::endSync() diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h index 2fef0ff1e8..899278843e 100644 --- a/src/quick/scenegraph/qsgcontext_p.h +++ b/src/quick/scenegraph/qsgcontext_p.h @@ -66,11 +66,10 @@ QT_BEGIN_NAMESPACE class QSGContextPrivate; -class QSGRectangleNode; -class QSGImageNode; +class QSGInternalRectangleNode; +class QSGInternalImageNode; class QSGPainterNode; class QSGGlyphNode; -class QSGNinePatchNode; class QSGRenderer; class QSGDistanceFieldGlyphCache; class QQuickWindow; @@ -85,6 +84,10 @@ class QQuickPaintedItem; class QSGRendererInterface; class QSGShaderEffectNode; class QSGGuiThreadShaderEffectManager; +class QSGRectangleNode; +class QSGImageNode; +class QSGNinePatchNode; +class QSGSpriteNode; Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_TIME_RENDERLOOP) Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_TIME_COMPILATION) @@ -122,6 +125,10 @@ public: virtual QSGTexture *createTexture(const QImage &image, uint flags = CreateTexture_Alpha) const = 0; virtual QSGRenderer *createRenderer() = 0; + virtual void setAttachToGraphicsContext(bool attach) { Q_UNUSED(attach); } + + virtual int maxTextureSize() const = 0; + void registerFontengineForCleanup(QFontEngine *engine); Q_SIGNALS: @@ -132,7 +139,8 @@ public Q_SLOTS: void textureFactoryDestroyed(QObject *o); protected: - QSGContext *m_sg; + // Hold m_sg with QPointer in the rare case it gets deleted before us. + QPointer<QSGContext> m_sg; QMutex m_mutex; QHash<QQuickTextureFactory *, QSGTexture *> m_textures; @@ -161,16 +169,16 @@ public: virtual void renderContextInvalidated(QSGRenderContext *renderContext); virtual QSGRenderContext *createRenderContext() = 0; - QSGRectangleNode *createRectangleNode(const QRectF &rect, const QColor &c); - virtual QSGRectangleNode *createRectangleNode() = 0; - virtual QSGImageNode *createImageNode() = 0; + QSGInternalRectangleNode *createInternalRectangleNode(const QRectF &rect, const QColor &c); + virtual QSGInternalRectangleNode *createInternalRectangleNode() = 0; + virtual QSGInternalImageNode *createInternalImageNode() = 0; virtual QSGPainterNode *createPainterNode(QQuickPaintedItem *item) = 0; virtual QSGGlyphNode *createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode) = 0; - virtual QSGNinePatchNode *createNinePatchNode() = 0; virtual QSGLayer *createLayer(QSGRenderContext *renderContext) = 0; virtual QSGGuiThreadShaderEffectManager *createGuiThreadShaderEffectManager(); virtual QSGShaderEffectNode *createShaderEffectNode(QSGRenderContext *renderContext, QSGGuiThreadShaderEffectManager *mgr); + virtual QSGSpriteNode *createSpriteNode() = 0; virtual QAnimationDriver *createAnimationDriver(QObject *parent); virtual QSize minimumFBOSize() const; @@ -178,6 +186,10 @@ public: virtual QSGRendererInterface *rendererInterface(QSGRenderContext *renderContext); + virtual QSGRectangleNode *createRectangleNode() = 0; + virtual QSGImageNode *createImageNode() = 0; + virtual QSGNinePatchNode *createNinePatchNode() = 0; + static QSGContext *createDefaultContext(); static QQuickTextureFactory *createTextureFactoryFromImage(const QImage &image); static QSGRenderLoop *createWindowManager(); diff --git a/src/quick/scenegraph/qsgcontextplugin.cpp b/src/quick/scenegraph/qsgcontextplugin.cpp index 7569cd2495..3751891455 100644 --- a/src/quick/scenegraph/qsgcontextplugin.cpp +++ b/src/quick/scenegraph/qsgcontextplugin.cpp @@ -136,9 +136,7 @@ QSGAdaptationBackendData *contextFactory() #endif if (!requestedBackend.isEmpty()) { -#ifndef QT_NO_DEBUG qCDebug(QSG_LOG_INFO) << "Loading backend" << requestedBackend; -#endif // First look for a built-in adaptation. for (QSGContextFactoryInterface *builtInBackend : qAsConst(backendData->builtIns)) { @@ -160,14 +158,12 @@ QSGAdaptationBackendData *contextFactory() backendData->name = requestedBackend; backendData->flags = backendData->factory->flags(requestedBackend); } -#ifndef QT_NO_DEBUG if (!backendData->factory) { qWarning("Could not create scene graph context for backend '%s'" " - check that plugins are installed correctly in %s", qPrintable(requestedBackend), qPrintable(QLibraryInfo::location(QLibraryInfo::PluginsPath))); } -#endif } #endif // QT_NO_LIBRARY } diff --git a/src/quick/scenegraph/qsgdefaultcontext.cpp b/src/quick/scenegraph/qsgdefaultcontext.cpp index f9978e816c..6964b74dc8 100644 --- a/src/quick/scenegraph/qsgdefaultcontext.cpp +++ b/src/quick/scenegraph/qsgdefaultcontext.cpp @@ -40,8 +40,8 @@ #include "qsgdefaultcontext_p.h" #include <QtQuick/private/qsgdistancefieldutil_p.h> -#include <QtQuick/private/qsgdefaultrectanglenode_p.h> -#include <QtQuick/private/qsgdefaultimagenode_p.h> +#include <QtQuick/private/qsgdefaultinternalrectanglenode_p.h> +#include <QtQuick/private/qsgdefaultinternalimagenode_p.h> #include <QtQuick/private/qsgdefaultpainternode_p.h> #include <QtQuick/private/qsgdefaultglyphnode_p.h> #include <QtQuick/private/qsgdistancefieldglyphnode_p.h> @@ -49,6 +49,10 @@ #include <QtQuick/private/qsgrenderloop_p.h> #include <QtQuick/private/qsgdefaultlayer_p.h> #include <QtQuick/private/qsgdefaultrendercontext_p.h> +#include <QtQuick/private/qsgdefaultrectanglenode_p.h> +#include <QtQuick/private/qsgdefaultimagenode_p.h> +#include <QtQuick/private/qsgdefaultninepatchnode_p.h> +#include <QtQuick/private/qsgdefaultspritenode_p.h> #include <QtGui/QOpenGLContext> #include <QtGui/QOpenGLFramebufferObject> @@ -60,13 +64,13 @@ QT_BEGIN_NAMESPACE namespace QSGMultisampleAntialiasing { - class ImageNode : public QSGDefaultImageNode { + class ImageNode : public QSGDefaultInternalImageNode { public: void setAntialiasing(bool) { } }; - class RectangleNode : public QSGDefaultRectangleNode { + class RectangleNode : public QSGDefaultInternalRectangleNode { public: void setAntialiasing(bool) { } }; @@ -152,7 +156,9 @@ void QSGDefaultContext::renderContextInitialized(QSGRenderContext *renderContext qCDebug(QSG_LOG_INFO) << "GL_RENDERER: " << (const char *) funcs->glGetString(GL_RENDERER); qCDebug(QSG_LOG_INFO) << "GL_VERSION: " << (const char *) funcs->glGetString(GL_VERSION); QSet<QByteArray> exts = openglRenderContext->openglContext()->extensions(); - QByteArray all; foreach (const QByteArray &e, exts) all += ' ' + e; + QByteArray all; + for (const QByteArray &e : qAsConst(exts)) + all += ' ' + e; qCDebug(QSG_LOG_INFO) << "GL_EXTENSIONS: " << all.constData(); qCDebug(QSG_LOG_INFO) << "Max Texture Size: " << openglRenderContext->maxTextureSize(); qCDebug(QSG_LOG_INFO) << "Debug context: " << format.testOption(QSurfaceFormat::DebugContext); @@ -170,18 +176,18 @@ QSGRenderContext *QSGDefaultContext::createRenderContext() return new QSGDefaultRenderContext(this); } -QSGRectangleNode *QSGDefaultContext::createRectangleNode() +QSGInternalRectangleNode *QSGDefaultContext::createInternalRectangleNode() { return m_antialiasingMethod == MsaaAntialiasing ? new QSGMultisampleAntialiasing::RectangleNode - : new QSGDefaultRectangleNode; + : new QSGDefaultInternalRectangleNode; } -QSGImageNode *QSGDefaultContext::createImageNode() +QSGInternalImageNode *QSGDefaultContext::createInternalImageNode() { return m_antialiasingMethod == MsaaAntialiasing ? new QSGMultisampleAntialiasing::ImageNode - : new QSGDefaultImageNode; + : new QSGDefaultInternalImageNode; } QSGPainterNode *QSGDefaultContext::createPainterNode(QQuickPaintedItem *item) @@ -200,15 +206,6 @@ QSGGlyphNode *QSGDefaultContext::createGlyphNode(QSGRenderContext *rc, bool pref } } -/*! - * Factory function for scene graph backends of the QStyle stylable elements. Returns a - * null pointer if the backend doesn't provide its own node type. - */ -QSGNinePatchNode *QSGDefaultContext::createNinePatchNode() -{ - return nullptr; -} - QSGLayer *QSGDefaultContext::createLayer(QSGRenderContext *renderContext) { return new QSGDefaultLayer(renderContext); @@ -246,6 +243,26 @@ QSGRendererInterface *QSGDefaultContext::rendererInterface(QSGRenderContext *ren return this; } +QSGRectangleNode *QSGDefaultContext::createRectangleNode() +{ + return new QSGDefaultRectangleNode; +} + +QSGImageNode *QSGDefaultContext::createImageNode() +{ + return new QSGDefaultImageNode; +} + +QSGNinePatchNode *QSGDefaultContext::createNinePatchNode() +{ + return new QSGDefaultNinePatchNode; +} + +QSGSpriteNode *QSGDefaultContext::createSpriteNode() +{ + return new QSGDefaultSpriteNode; +} + QSGRendererInterface::GraphicsApi QSGDefaultContext::graphicsApi() const { return OpenGL; @@ -263,7 +280,7 @@ QSGRendererInterface::ShaderCompilationTypes QSGDefaultContext::shaderCompilatio QSGRendererInterface::ShaderSourceTypes QSGDefaultContext::shaderSourceType() const { - return ShaderSourceString; + return ShaderSourceString | ShaderSourceFile; } QT_END_NAMESPACE diff --git a/src/quick/scenegraph/qsgdefaultcontext_p.h b/src/quick/scenegraph/qsgdefaultcontext_p.h index 6686ab98a0..88db5e1e9a 100644 --- a/src/quick/scenegraph/qsgdefaultcontext_p.h +++ b/src/quick/scenegraph/qsgdefaultcontext_p.h @@ -57,7 +57,7 @@ QT_BEGIN_NAMESPACE -class QSGDefaultContext : public QSGContext, public QSGRendererInterface +class Q_QUICK_PRIVATE_EXPORT QSGDefaultContext : public QSGContext, public QSGRendererInterface { public: QSGDefaultContext(QObject *parent = 0); @@ -66,14 +66,17 @@ public: void renderContextInitialized(QSGRenderContext *renderContext) override; void renderContextInvalidated(QSGRenderContext *) override; QSGRenderContext *createRenderContext() override; - QSGRectangleNode *createRectangleNode() override; - QSGImageNode *createImageNode() override; + QSGInternalRectangleNode *createInternalRectangleNode() override; + QSGInternalImageNode *createInternalImageNode() override; QSGPainterNode *createPainterNode(QQuickPaintedItem *item) override; QSGGlyphNode *createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode) override; - QSGNinePatchNode *createNinePatchNode() override; QSGLayer *createLayer(QSGRenderContext *renderContext) override; QSurfaceFormat defaultSurfaceFormat() const override; QSGRendererInterface *rendererInterface(QSGRenderContext *renderContext) override; + QSGRectangleNode *createRectangleNode() override; + QSGImageNode *createImageNode() override; + QSGNinePatchNode *createNinePatchNode() override; + QSGSpriteNode *createSpriteNode() override; void setDistanceFieldEnabled(bool enabled); bool isDistanceFieldEnabled() const; diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp index 650700e37a..f0a336e229 100644 --- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp +++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp @@ -103,8 +103,10 @@ void QSGDefaultDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyph glyph_t glyphIndex = *it; int padding = QSG_DEFAULT_DISTANCEFIELD_GLYPH_CACHE_PADDING; - int glyphWidth = qCeil(glyphData(glyphIndex).boundingRect.width()) + distanceFieldRadius() * 2; - QSize glyphSize(glyphWidth + padding * 2, QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution()) + padding * 2); + QRectF boundingRect = glyphData(glyphIndex).boundingRect; + int glyphWidth = qCeil(boundingRect.width()) + distanceFieldRadius() * 2; + int glyphHeight = qCeil(boundingRect.height()) + distanceFieldRadius() * 2; + QSize glyphSize(glyphWidth + padding * 2, glyphHeight + padding * 2); QRect alloc = m_areaAllocator->allocate(glyphSize); if (alloc.isNull()) { @@ -113,11 +115,13 @@ void QSGDefaultDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyph glyph_t unusedGlyph = *m_unusedGlyphs.constBegin(); TexCoord unusedCoord = glyphTexCoord(unusedGlyph); - int unusedGlyphWidth = qCeil(glyphData(unusedGlyph).boundingRect.width()) + distanceFieldRadius() * 2; + QRectF unusedGlyphBoundingRect = glyphData(unusedGlyph).boundingRect; + int unusedGlyphWidth = qCeil(unusedGlyphBoundingRect.width()) + distanceFieldRadius() * 2; + int unusedGlyphHeight = qCeil(unusedGlyphBoundingRect.height()) + distanceFieldRadius() * 2; m_areaAllocator->deallocate(QRect(unusedCoord.x - padding, unusedCoord.y - padding, padding * 2 + unusedGlyphWidth, - padding * 2 + QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution()))); + padding * 2 + unusedGlyphHeight)); m_unusedGlyphs.remove(unusedGlyph); m_glyphsTexture.remove(unusedGlyph); @@ -255,7 +259,8 @@ void QSGDefaultDistanceFieldGlyphCache::createTexture(TextureInfo *texInfo, int const GLenum format = GL_ALPHA; #endif - m_funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, 0); + QByteArray zeroBuf(width * height, 0); + m_funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, zeroBuf.constData()); texInfo->size = QSize(width, height); diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h index eeea104e91..9ad99e5c54 100644 --- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h +++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h @@ -116,9 +116,8 @@ private: { m_blitProgram = new QOpenGLShaderProgram; { - QString source; - source.append(QLatin1String(qopenglslMainWithTexCoordsVertexShader)); - source.append(QLatin1String(qopenglslUntransformedPositionVertexShader)); + const QString source = QLatin1String(qopenglslMainWithTexCoordsVertexShader) + + QLatin1String(qopenglslUntransformedPositionVertexShader); QOpenGLShader *vertexShader = new QOpenGLShader(QOpenGLShader::Vertex, m_blitProgram); vertexShader->compileSourceCode(source); @@ -126,9 +125,8 @@ private: m_blitProgram->addShader(vertexShader); } { - QString source; - source.append(QLatin1String(qopenglslMainFragmentShader)); - source.append(QLatin1String(qopenglslImageSrcFragmentShader)); + const QString source = QLatin1String(qopenglslMainFragmentShader) + + QLatin1String(qopenglslImageSrcFragmentShader); QOpenGLShader *fragmentShader = new QOpenGLShader(QOpenGLShader::Fragment, m_blitProgram); fragmentShader->compileSourceCode(source); diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp index 7c2663d5a3..3501f30487 100644 --- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp +++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp @@ -41,6 +41,7 @@ #include <private/qsgmaterialshader_p.h> #include <qopenglshaderprogram.h> +#include <qopenglframebufferobject.h> #include <QtGui/private/qguiapplication_p.h> #include <qpa/qplatformintegration.h> @@ -210,6 +211,7 @@ public: void activate(); void deactivate(); + bool useSRGB() const; uint m_useSRGB : 1; }; @@ -229,11 +231,26 @@ void QSG24BitTextMaskShader::initialize() } } +bool QSG24BitTextMaskShader::useSRGB() const +{ +#ifdef Q_OS_MACOS + if (!m_useSRGB) + return false; + + // m_useSRGB is true, but if some QOGLFBO was bound check it's texture format: + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + QOpenGLFramebufferObject *qfbo = QOpenGLContextPrivate::get(ctx)->qgl_current_fbo; + return !qfbo || qfbo->format().internalTextureFormat() == GL_SRGB8_ALPHA8_EXT; +#else + return m_useSRGB; +#endif +} + void QSG24BitTextMaskShader::activate() { QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); funcs->glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR); - if (m_useSRGB) + if (useSRGB()) funcs->glEnable(GL_FRAMEBUFFER_SRGB); } @@ -241,7 +258,7 @@ void QSG24BitTextMaskShader::deactivate() { QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); funcs->glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - if (m_useSRGB) + if (useSRGB()) funcs->glDisable(GL_FRAMEBUFFER_SRGB); } @@ -266,7 +283,7 @@ void QSG24BitTextMaskShader::updateState(const RenderState &state, QSGMaterial * if (oldMaterial == 0 || material->color() != oldMaterial->color() || state.isOpacityDirty()) { QVector4D color = material->color(); - if (m_useSRGB) + if (useSRGB()) color = qt_sRGB_to_linear_RGB(color); QOpenGLContext::currentContext()->functions()->glBlendColor(color.x(), color.y(), color.z(), color.w()); color = qsg_premultiply(color, state.opacity()); diff --git a/src/quick/scenegraph/qsgdefaultimagenode.cpp b/src/quick/scenegraph/qsgdefaultinternalimagenode.cpp index 9fed70a7de..1d54628acd 100644 --- a/src/quick/scenegraph/qsgdefaultimagenode.cpp +++ b/src/quick/scenegraph/qsgdefaultinternalimagenode.cpp @@ -37,7 +37,7 @@ ** ****************************************************************************/ -#include "qsgdefaultimagenode_p.h" +#include "qsgdefaultinternalimagenode_p.h" #include <private/qsgmaterialshader_p.h> #include <private/qsgtexturematerial_p.h> #include <QtGui/qopenglfunctions.h> @@ -117,13 +117,13 @@ void SmoothTextureMaterialShader::initialize() QSGTextureMaterialShader::initialize(); } -QSGDefaultImageNode::QSGDefaultImageNode() +QSGDefaultInternalImageNode::QSGDefaultInternalImageNode() { setMaterial(&m_materialO); setOpaqueMaterial(&m_material); } -void QSGDefaultImageNode::setFiltering(QSGTexture::Filtering filtering) +void QSGDefaultInternalImageNode::setFiltering(QSGTexture::Filtering filtering) { if (m_material.filtering() == filtering) return; @@ -134,7 +134,7 @@ void QSGDefaultImageNode::setFiltering(QSGTexture::Filtering filtering) markDirty(DirtyMaterial); } -void QSGDefaultImageNode::setMipmapFiltering(QSGTexture::Filtering filtering) +void QSGDefaultInternalImageNode::setMipmapFiltering(QSGTexture::Filtering filtering) { if (m_material.mipmapFiltering() == filtering) return; @@ -145,7 +145,7 @@ void QSGDefaultImageNode::setMipmapFiltering(QSGTexture::Filtering filtering) markDirty(DirtyMaterial); } -void QSGDefaultImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrapMode) +void QSGDefaultInternalImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrapMode) { if (m_material.verticalWrapMode() == wrapMode) return; @@ -156,7 +156,7 @@ void QSGDefaultImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrapMode) markDirty(DirtyMaterial); } -void QSGDefaultImageNode::setHorizontalWrapMode(QSGTexture::WrapMode wrapMode) +void QSGDefaultInternalImageNode::setHorizontalWrapMode(QSGTexture::WrapMode wrapMode) { if (m_material.horizontalWrapMode() == wrapMode) return; @@ -167,7 +167,7 @@ void QSGDefaultImageNode::setHorizontalWrapMode(QSGTexture::WrapMode wrapMode) markDirty(DirtyMaterial); } -void QSGDefaultImageNode::updateMaterialAntialiasing() +void QSGDefaultInternalImageNode::updateMaterialAntialiasing() { if (m_antialiasing) { setMaterial(&m_smoothMaterial); @@ -178,19 +178,19 @@ void QSGDefaultImageNode::updateMaterialAntialiasing() } } -void QSGDefaultImageNode::setMaterialTexture(QSGTexture *texture) +void QSGDefaultInternalImageNode::setMaterialTexture(QSGTexture *texture) { m_material.setTexture(texture); m_materialO.setTexture(texture); m_smoothMaterial.setTexture(texture); } -QSGTexture *QSGDefaultImageNode::materialTexture() const +QSGTexture *QSGDefaultInternalImageNode::materialTexture() const { return m_material.texture(); } -bool QSGDefaultImageNode::updateMaterialBlending() +bool QSGDefaultInternalImageNode::updateMaterialBlending() { const bool alpha = m_material.flags() & QSGMaterial::Blending; if (materialTexture() && alpha != materialTexture()->hasAlphaChannel()) { @@ -206,7 +206,7 @@ inline static bool isPowerOfTwo(int x) return x == (x & -x); } -bool QSGDefaultImageNode::supportsWrap(const QSize &size) const +bool QSGDefaultInternalImageNode::supportsWrap(const QSize &size) const { bool wrapSupported = true; diff --git a/src/quick/scenegraph/qsgdefaultimagenode_p.h b/src/quick/scenegraph/qsgdefaultinternalimagenode_p.h index 688c5a5039..1fc7834bd1 100644 --- a/src/quick/scenegraph/qsgdefaultimagenode_p.h +++ b/src/quick/scenegraph/qsgdefaultinternalimagenode_p.h @@ -38,8 +38,8 @@ ****************************************************************************/ -#ifndef QSGDEFAULTIMAGENODE_P_H -#define QSGDEFAULTIMAGENODE_P_H +#ifndef QSGDEFAULTINTERNALIMAGENODE_P_H +#define QSGDEFAULTINTERNALIMAGENODE_P_H // // W A R N I N G @@ -53,7 +53,7 @@ // #include <private/qsgadaptationlayer_p.h> -#include <private/qsgbasicimagenode_p.h> +#include <private/qsgbasicinternalimagenode_p.h> #include <QtQuick/qsgtexturematerial.h> QT_BEGIN_NAMESPACE @@ -70,10 +70,10 @@ protected: QSGMaterialShader *createShader() const override; }; -class Q_QUICK_PRIVATE_EXPORT QSGDefaultImageNode : public QSGBasicImageNode +class Q_QUICK_PRIVATE_EXPORT QSGDefaultInternalImageNode : public QSGBasicInternalImageNode { public: - QSGDefaultImageNode(); + QSGDefaultInternalImageNode(); void setMipmapFiltering(QSGTexture::Filtering filtering) override; void setFiltering(QSGTexture::Filtering filtering) override; diff --git a/src/quick/scenegraph/qsgdefaultrectanglenode.cpp b/src/quick/scenegraph/qsgdefaultinternalrectanglenode.cpp index 117a9272e5..94414444ba 100644 --- a/src/quick/scenegraph/qsgdefaultrectanglenode.cpp +++ b/src/quick/scenegraph/qsgdefaultinternalrectanglenode.cpp @@ -38,7 +38,7 @@ ** ****************************************************************************/ -#include "qsgdefaultrectanglenode_p.h" +#include "qsgdefaultinternalrectanglenode_p.h" #include <QtQuick/qsgvertexcolormaterial.h> #include <QtQuick/qsgtexturematerial.h> @@ -128,12 +128,12 @@ QSGMaterialShader *QSGSmoothColorMaterial::createShader() const return new SmoothColorMaterialShader; } -QSGDefaultRectangleNode::QSGDefaultRectangleNode() +QSGDefaultInternalRectangleNode::QSGDefaultInternalRectangleNode() { setMaterial(&m_material); } -void QSGDefaultRectangleNode::updateMaterialAntialiasing() +void QSGDefaultInternalRectangleNode::updateMaterialAntialiasing() { if (m_antialiasing) setMaterial(&m_smoothMaterial); @@ -141,7 +141,7 @@ void QSGDefaultRectangleNode::updateMaterialAntialiasing() setMaterial(&m_material); } -void QSGDefaultRectangleNode::updateMaterialBlending(QSGNode::DirtyState *state) +void QSGDefaultInternalRectangleNode::updateMaterialBlending(QSGNode::DirtyState *state) { // smoothed material is always blended, so no change in material state if (material() == &m_material) { diff --git a/src/quick/scenegraph/qsgdefaultrectanglenode_p.h b/src/quick/scenegraph/qsgdefaultinternalrectanglenode_p.h index f30a3beed7..a3f734a7b3 100644 --- a/src/quick/scenegraph/qsgdefaultrectanglenode_p.h +++ b/src/quick/scenegraph/qsgdefaultinternalrectanglenode_p.h @@ -38,8 +38,8 @@ ****************************************************************************/ -#ifndef QSGDEFAULTRECTANGLENODE_P_H -#define QSGDEFAULTRECTANGLENODE_P_H +#ifndef QSGDEFAULTINTERNALRECTANGLENODE_P_H +#define QSGDEFAULTINTERNALRECTANGLENODE_P_H // // W A R N I N G @@ -53,7 +53,7 @@ // #include <private/qsgadaptationlayer_p.h> -#include <private/qsgbasicrectanglenode_p.h> +#include <private/qsgbasicinternalrectanglenode_p.h> #include <QtQuick/qsgvertexcolormaterial.h> QT_BEGIN_NAMESPACE @@ -65,17 +65,17 @@ class Q_QUICK_PRIVATE_EXPORT QSGSmoothColorMaterial : public QSGMaterial public: QSGSmoothColorMaterial(); - int compare(const QSGMaterial *other) const; + int compare(const QSGMaterial *other) const override; protected: QSGMaterialType *type() const override; QSGMaterialShader *createShader() const override; }; -class Q_QUICK_PRIVATE_EXPORT QSGDefaultRectangleNode : public QSGBasicRectangleNode +class Q_QUICK_PRIVATE_EXPORT QSGDefaultInternalRectangleNode : public QSGBasicInternalRectangleNode { public: - QSGDefaultRectangleNode(); + QSGDefaultInternalRectangleNode(); private: void updateMaterialAntialiasing() override; diff --git a/src/quick/scenegraph/qsgdefaultrendercontext.cpp b/src/quick/scenegraph/qsgdefaultrendercontext.cpp index 92e7f983a0..6f10611ba3 100644 --- a/src/quick/scenegraph/qsgdefaultrendercontext.cpp +++ b/src/quick/scenegraph/qsgdefaultrendercontext.cpp @@ -70,6 +70,9 @@ QSGDefaultRenderContext::QSGDefaultRenderContext(QSGContext *context) */ void QSGDefaultRenderContext::initialize(void *context) { + if (!m_sg) + return; + QOpenGLContext *openglContext = static_cast<QOpenGLContext *>(context); QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); @@ -163,7 +166,9 @@ void QSGDefaultRenderContext::invalidate() m_gl->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant()); m_gl = 0; - QSGRenderContext::invalidate(); + if (m_sg) + m_sg->renderContextInvalidated(this); + emit invalidated(); } static QBasicMutex qsg_framerender_mutex; @@ -273,7 +278,7 @@ void QSGDefaultRenderContext::initializeShader(QSGMaterialShader *shader) shader->initialize(); } -void QSGDefaultRenderContext::setAttachToGLContext(bool attach) +void QSGDefaultRenderContext::setAttachToGraphicsContext(bool attach) { Q_ASSERT(!isValid()); m_attachToGLContext = attach; diff --git a/src/quick/scenegraph/qsgdefaultrendercontext_p.h b/src/quick/scenegraph/qsgdefaultrendercontext_p.h index bfb15b1eb9..0aed46b658 100644 --- a/src/quick/scenegraph/qsgdefaultrendercontext_p.h +++ b/src/quick/scenegraph/qsgdefaultrendercontext_p.h @@ -64,7 +64,7 @@ namespace QSGAtlasTexture { class Manager; } -class QSGDefaultRenderContext : public QSGRenderContext +class Q_QUICK_PRIVATE_EXPORT QSGDefaultRenderContext : public QSGRenderContext { Q_OBJECT public: @@ -88,12 +88,12 @@ public: virtual void compileShader(QSGMaterialShader *shader, QSGMaterial *material, const char *vertexCode = 0, const char *fragmentCode = 0); virtual void initializeShader(QSGMaterialShader *shader); - void setAttachToGLContext(bool attach); + void setAttachToGraphicsContext(bool attach) override; static QSGDefaultRenderContext *from(QOpenGLContext *context); bool hasBrokenIndexBufferObjects() const { return m_brokenIBOs; } - int maxTextureSize() const { return m_maxTextureSize; } + int maxTextureSize() const override { return m_maxTextureSize; } protected: QOpenGLContext *m_gl; diff --git a/src/quick/scenegraph/qsgdefaultspritenode.cpp b/src/quick/scenegraph/qsgdefaultspritenode.cpp new file mode 100644 index 0000000000..89b26f8660 --- /dev/null +++ b/src/quick/scenegraph/qsgdefaultspritenode.cpp @@ -0,0 +1,303 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgdefaultspritenode_p.h" + +#include <QtQuick/QSGMaterial> +#include <QtGui/QOpenGLShaderProgram> + +QT_BEGIN_NAMESPACE + +struct SpriteVertex { + float x; + float y; + float tx; + float ty; +}; + +struct SpriteVertices { + SpriteVertex v1; + SpriteVertex v2; + SpriteVertex v3; + SpriteVertex v4; +}; + +class QQuickSpriteMaterial : public QSGMaterial +{ +public: + QQuickSpriteMaterial(); + ~QQuickSpriteMaterial(); + QSGMaterialType *type() const override { static QSGMaterialType type; return &type; } + QSGMaterialShader *createShader() const override; + int compare(const QSGMaterial *other) const override + { + return this - static_cast<const QQuickSpriteMaterial *>(other); + } + + QSGTexture *texture; + + float animT; + float animX1; + float animY1; + float animX2; + float animY2; + float animW; + float animH; +}; + +QQuickSpriteMaterial::QQuickSpriteMaterial() + : texture(0) + , animT(0.0f) + , animX1(0.0f) + , animY1(0.0f) + , animX2(0.0f) + , animY2(0.0f) + , animW(1.0f) + , animH(1.0f) +{ + setFlag(Blending, true); +} + +QQuickSpriteMaterial::~QQuickSpriteMaterial() +{ + delete texture; +} + +class SpriteMaterialData : public QSGMaterialShader +{ +public: + SpriteMaterialData() + : QSGMaterialShader() + { + setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/scenegraph/shaders/sprite.vert")); + setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/sprite.frag")); + } + + void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *) Q_DECL_OVERRIDE + { + QQuickSpriteMaterial *m = static_cast<QQuickSpriteMaterial *>(newEffect); + m->texture->bind(); + + program()->setUniformValue(m_opacity_id, state.opacity()); + program()->setUniformValue(m_animData_id, m->animW, m->animH, m->animT); + program()->setUniformValue(m_animPos_id, m->animX1, m->animY1, m->animX2, m->animY2); + + if (state.isMatrixDirty()) + program()->setUniformValue(m_matrix_id, state.combinedMatrix()); + } + + void initialize() Q_DECL_OVERRIDE { + m_matrix_id = program()->uniformLocation("qt_Matrix"); + m_opacity_id = program()->uniformLocation("qt_Opacity"); + m_animData_id = program()->uniformLocation("animData"); + m_animPos_id = program()->uniformLocation("animPos"); + } + + char const *const *attributeNames() const Q_DECL_OVERRIDE { + static const char *attr[] = { + "vPos", + "vTex", + 0 + }; + return attr; + } + + int m_matrix_id; + int m_opacity_id; + int m_animData_id; + int m_animPos_id; +}; + +QSGMaterialShader *QQuickSpriteMaterial::createShader() const +{ + return new SpriteMaterialData; +} + +static QSGGeometry::Attribute Sprite_Attributes[] = { + QSGGeometry::Attribute::create(0, 2, QSGGeometry::TypeFloat, true), // pos + QSGGeometry::Attribute::create(1, 2, QSGGeometry::TypeFloat), // tex +}; + +static QSGGeometry::AttributeSet Sprite_AttributeSet = +{ + 2, // Attribute Count + (2+2) * sizeof(float), + Sprite_Attributes +}; + +QSGDefaultSpriteNode::QSGDefaultSpriteNode() + : m_material(new QQuickSpriteMaterial) + , m_geometryDirty(true) + , m_sheetSize(QSize(64, 64)) +{ + // Setup geometry data + m_geometry = new QSGGeometry(Sprite_AttributeSet, 4, 6); + m_geometry->setDrawingMode(QSGGeometry::DrawTriangles); + quint16 *indices = m_geometry->indexDataAsUShort(); + indices[0] = 0; + indices[1] = 1; + indices[2] = 2; + indices[3] = 1; + indices[4] = 3; + indices[5] = 2; + + setGeometry(m_geometry); + setMaterial(m_material); + setFlag(OwnsGeometry, true); + setFlag(OwnsMaterial, true); +} + +void QSGDefaultSpriteNode::setTexture(QSGTexture *texture) +{ + m_material->texture = texture; + m_geometryDirty = true; + markDirty(DirtyMaterial); +} + +void QSGDefaultSpriteNode::setTime(float time) +{ + m_material->animT = time; + markDirty(DirtyMaterial); +} + +void QSGDefaultSpriteNode::setSourceA(const QPoint &source) +{ + if (m_sourceA != source) { + m_sourceA = source; + m_material->animX1 = static_cast<float>(source.x()) / m_sheetSize.width(); + m_material->animY1 = static_cast<float>(source.y()) / m_sheetSize.height(); + markDirty(DirtyMaterial); + } +} + +void QSGDefaultSpriteNode::setSourceB(const QPoint &source) +{ + if (m_sourceB != source) { + m_sourceB = source; + m_material->animX2 = static_cast<float>(source.x()) / m_sheetSize.width(); + m_material->animY2 = static_cast<float>(source.y()) / m_sheetSize.height(); + markDirty(DirtyMaterial); + } +} + +void QSGDefaultSpriteNode::setSpriteSize(const QSize &size) +{ + if (m_spriteSize != size) { + m_spriteSize = size; + m_material->animW = static_cast<float>(size.width()) / m_sheetSize.width(); + m_material->animH = static_cast<float>(size.height()) / m_sheetSize.height(); + markDirty(DirtyMaterial); + } + +} + +void QSGDefaultSpriteNode::setSheetSize(const QSize &size) +{ + if (m_sheetSize != size) { + m_sheetSize = size; + + // Update all dependent properties + m_material->animX1 = static_cast<float>(m_sourceA.x()) / m_sheetSize.width(); + m_material->animY1 = static_cast<float>(m_sourceA.y()) / m_sheetSize.height(); + m_material->animX2 = static_cast<float>(m_sourceB.x()) / m_sheetSize.width(); + m_material->animY2 = static_cast<float>(m_sourceB.y()) / m_sheetSize.height(); + m_material->animW = static_cast<float>(m_spriteSize.width()) / m_sheetSize.width(); + m_material->animH = static_cast<float>(m_spriteSize.height()) / m_sheetSize.height(); + markDirty(DirtyMaterial); + } +} + +void QSGDefaultSpriteNode::setSize(const QSizeF &size) +{ + if (m_size != size) { + m_size = size; + m_geometryDirty = true; + } +} + +void QSGDefaultSpriteNode::setFiltering(QSGTexture::Filtering filtering) +{ + m_material->texture->setFiltering(filtering); + markDirty(DirtyMaterial); +} + +void QSGDefaultSpriteNode::update() +{ + if (m_geometryDirty) { + updateGeometry(); + m_geometryDirty = false; + } +} + +void QSGDefaultSpriteNode::updateGeometry() +{ + if (!m_material->texture) + return; + + SpriteVertices *p = (SpriteVertices *) m_geometry->vertexData(); + + QRectF texRect = m_material->texture->normalizedTextureSubRect(); + + p->v1.tx = texRect.topLeft().x(); + p->v1.ty = texRect.topLeft().y(); + + p->v2.tx = texRect.topRight().x(); + p->v2.ty = texRect.topRight().y(); + + p->v3.tx = texRect.bottomLeft().x(); + p->v3.ty = texRect.bottomLeft().y(); + + p->v4.tx = texRect.bottomRight().x(); + p->v4.ty = texRect.bottomRight().y(); + + p->v1.x = 0; + p->v1.y = 0; + + p->v2.x = m_size.width(); + p->v2.y = 0; + + p->v3.x = 0; + p->v3.y = m_size.height(); + + p->v4.x = m_size.width(); + p->v4.y = m_size.height(); + markDirty(DirtyGeometry); +} + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/qsgdefaultspritenode_p.h b/src/quick/scenegraph/qsgdefaultspritenode_p.h new file mode 100644 index 0000000000..cb76bf8d83 --- /dev/null +++ b/src/quick/scenegraph/qsgdefaultspritenode_p.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGDEFAULTSPRITENODE_H +#define QSGDEFAULTSPRITENODE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt 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. +// + +#include <private/qsgadaptationlayer_p.h> + +QT_BEGIN_NAMESPACE +class QQuickSpriteMaterial; +class QSGDefaultSpriteNode : public QSGSpriteNode +{ +public: + QSGDefaultSpriteNode(); + + void setTexture(QSGTexture *texture) override; + void setTime(float time) override; + void setSourceA(const QPoint &source) override; + void setSourceB(const QPoint &source) override; + void setSpriteSize(const QSize &size) override; + void setSheetSize(const QSize &size) override; + void setSize(const QSizeF &size) override; + void setFiltering(QSGTexture::Filtering filtering) override; + void update() override; +private: + void updateGeometry(); + + QQuickSpriteMaterial *m_material; + QSGGeometry *m_geometry; + bool m_geometryDirty; + QPoint m_sourceA; + QPoint m_sourceB; + QSize m_spriteSize; + QSize m_sheetSize; + QSizeF m_size; +}; + +QT_END_NAMESPACE + +#endif // QSGDEFAULTSPRITENODE_H diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp index 1a9b576af4..a59f9ddcc7 100644 --- a/src/quick/scenegraph/qsgrenderloop.cpp +++ b/src/quick/scenegraph/qsgrenderloop.cpp @@ -100,7 +100,7 @@ void QSGRenderLoop::cleanup() { if (!s_instance) return; - foreach (QQuickWindow *w, s_instance->windows()) { + for (QQuickWindow *w : s_instance->windows()) { QQuickWindowPrivate *wd = QQuickWindowPrivate::get(w); if (wd->windowManager == s_instance) { s_instance->windowDestroyed(w); @@ -209,11 +209,11 @@ QSGRenderLoop *QSGRenderLoop::instance() if (Q_UNLIKELY(qEnvironmentVariableIsSet("QSG_RENDER_LOOP"))) { const QByteArray loopName = qgetenv("QSG_RENDER_LOOP"); - if (loopName == QByteArrayLiteral("windows")) + if (loopName == "windows") loopType = WindowsRenderLoop; - else if (loopName == QByteArrayLiteral("basic")) + else if (loopName == "basic") loopType = BasicRenderLoop; - else if (loopName == QByteArrayLiteral("threaded")) + else if (loopName == "threaded") loopType = ThreadedRenderLoop; } diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index 3ff32b360d..6b9c67b2bd 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -600,7 +600,7 @@ void QSGRenderThread::syncAndRender() #endif Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame); - if (!syncResultedInChanges && !repaintRequested) { + if (!syncResultedInChanges && !repaintRequested && sgrc->isValid()) { qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- no changes, render aborted"; int waitTime = vsyncDelta - (int) waitTimer.elapsed(); if (waitTime > 0) diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp index 371f512c6e..743e524a36 100644 --- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp +++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp @@ -263,7 +263,7 @@ void QSGWindowsRenderLoop::windowDestroyed(QQuickWindow *window) bool QSGWindowsRenderLoop::anyoneShowing() const { - foreach (const WindowData &wd, m_windows) + for (const WindowData &wd : qAsConst(m_windows)) if (wd.window->isVisible() && wd.window->isExposed() && wd.window->size().isValid()) return true; return false; @@ -382,7 +382,7 @@ void QSGWindowsRenderLoop::render() { RLDEBUG("render"); bool rendered = false; - foreach (const WindowData &wd, m_windows) { + for (const WindowData &wd : qAsConst(m_windows)) { if (wd.pendingUpdate) { const_cast<WindowData &>(wd).pendingUpdate = false; renderWindow(wd.window); diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri index d8dfd01e7a..a659ca5e10 100644 --- a/src/quick/scenegraph/scenegraph.pri +++ b/src/quick/scenegraph/scenegraph.pri @@ -1,5 +1,3 @@ -!contains(QT_CONFIG, egl):DEFINES += QT_NO_EGL - # DEFINES += QSG_SEPARATE_INDEX_BUFFER # DEFINES += QSG_DISTANCEFIELD_CACHE_DEBUG @@ -29,7 +27,7 @@ SOURCES += \ $$PWD/coreapi/qsgrendernode.cpp \ $$PWD/coreapi/qsgrendererinterface.cpp -contains(QT_CONFIG, opengl(es1|es2)?) { +qtConfig(opengl(es1|es2)?) { HEADERS += \ $$PWD/coreapi/qsgbatchrenderer_p.h SOURCES += \ @@ -52,7 +50,10 @@ HEADERS += \ $$PWD/util/qsgsimplematerial.h \ $$PWD/util/qsgtexturematerial.h \ $$PWD/util/qsgtexturematerial_p.h \ - $$PWD/util/qsgvertexcolormaterial.h + $$PWD/util/qsgvertexcolormaterial.h \ + $$PWD/util/qsgrectanglenode.h \ + $$PWD/util/qsgimagenode.h \ + $$PWD/util/qsgninepatchnode.h SOURCES += \ $$PWD/util/qsgareaallocator.cpp \ @@ -65,8 +66,12 @@ SOURCES += \ $$PWD/util/qsgflatcolormaterial.cpp \ $$PWD/util/qsgsimplematerial.cpp \ $$PWD/util/qsgtexturematerial.cpp \ - $$PWD/util/qsgvertexcolormaterial.cpp -contains(QT_CONFIG, opengl(es1|es2)?) { + $$PWD/util/qsgvertexcolormaterial.cpp \ + $$PWD/util/qsgrectanglenode.cpp \ + $$PWD/util/qsgimagenode.cpp \ + $$PWD/util/qsgninepatchnode.cpp + +qtConfig(opengl(es1|es2)?) { HEADERS += \ $$PWD/util/qsgdepthstencilbuffer_p.h \ $$PWD/util/qsgshadersourcebuilder_p.h \ @@ -83,8 +88,8 @@ HEADERS += \ $$PWD/qsgadaptationlayer_p.h \ $$PWD/qsgcontext_p.h \ $$PWD/qsgcontextplugin_p.h \ - $$PWD/qsgbasicrectanglenode_p.h \ - $$PWD/qsgbasicimagenode_p.h \ + $$PWD/qsgbasicinternalrectanglenode_p.h \ + $$PWD/qsgbasicinternalimagenode_p.h \ $$PWD/qsgbasicglyphnode_p.h \ $$PWD/qsgrenderloop_p.h @@ -92,23 +97,27 @@ SOURCES += \ $$PWD/qsgadaptationlayer.cpp \ $$PWD/qsgcontext.cpp \ $$PWD/qsgcontextplugin.cpp \ - $$PWD/qsgbasicrectanglenode.cpp \ - $$PWD/qsgbasicimagenode.cpp \ + $$PWD/qsgbasicinternalrectanglenode.cpp \ + $$PWD/qsgbasicinternalimagenode.cpp \ $$PWD/qsgbasicglyphnode.cpp \ $$PWD/qsgrenderloop.cpp -contains(QT_CONFIG, opengl(es1|es2)?) { +qtConfig(opengl(es1|es2)?) { SOURCES += \ $$PWD/qsgdefaultglyphnode.cpp \ $$PWD/qsgdefaultglyphnode_p.cpp \ $$PWD/qsgdefaultdistancefieldglyphcache.cpp \ $$PWD/qsgdistancefieldglyphnode.cpp \ $$PWD/qsgdistancefieldglyphnode_p.cpp \ - $$PWD/qsgdefaultimagenode.cpp \ - $$PWD/qsgdefaultrectanglenode.cpp \ + $$PWD/qsgdefaultinternalimagenode.cpp \ + $$PWD/qsgdefaultinternalrectanglenode.cpp \ $$PWD/qsgdefaultrendercontext.cpp \ $$PWD/qsgdefaultcontext.cpp \ + $$PWD/qsgdefaultspritenode.cpp \ $$PWD/util/qsgdefaultpainternode.cpp \ + $$PWD/util/qsgdefaultrectanglenode.cpp \ + $$PWD/util/qsgdefaultimagenode.cpp \ + $$PWD/util/qsgdefaultninepatchnode.cpp \ $$PWD/qsgdefaultlayer.cpp \ $$PWD/qsgthreadedrenderloop.cpp \ $$PWD/qsgwindowsrenderloop.cpp @@ -118,11 +127,15 @@ contains(QT_CONFIG, opengl(es1|es2)?) { $$PWD/qsgdistancefieldglyphnode_p.h \ $$PWD/qsgdistancefieldglyphnode_p_p.h \ $$PWD/qsgdefaultglyphnode_p_p.h \ - $$PWD/qsgdefaultimagenode_p.h \ - $$PWD/qsgdefaultrectanglenode_p.h \ + $$PWD/qsgdefaultinternalimagenode_p.h \ + $$PWD/qsgdefaultinternalrectanglenode_p.h \ + $$PWD/qsgdefaultspritenode_p.h \ $$PWD/qsgdefaultrendercontext_p.h \ $$PWD/qsgdefaultcontext_p.h \ $$PWD/util/qsgdefaultpainternode_p.h \ + $$PWD/util/qsgdefaultrectanglenode_p.h \ + $$PWD/util/qsgdefaultimagenode_p.h \ + $$PWD/util/qsgdefaultninepatchnode_p.h \ $$PWD/qsgdefaultlayer_p.h \ $$PWD/qsgthreadedrenderloop_p.h \ $$PWD/qsgwindowsrenderloop_p.h @@ -135,7 +148,7 @@ RESOURCES += \ $$PWD/scenegraph.qrc # OpenGL Shaders -contains(QT_CONFIG, opengl(es1|es2)?) { +qtConfig(opengl(es1|es2)?) { OTHER_FILES += \ $$PWD/shaders/24bittextmask.frag \ $$PWD/shaders/8bittextmask.frag \ diff --git a/src/quick/scenegraph/scenegraph.qrc b/src/quick/scenegraph/scenegraph.qrc index ef6da71334..0687530be1 100644 --- a/src/quick/scenegraph/scenegraph.qrc +++ b/src/quick/scenegraph/scenegraph.qrc @@ -68,5 +68,9 @@ <file>shaders/vertexcolor_core.vert</file> <file>shaders/visualization.vert</file> <file>shaders/visualization.frag</file> + <file>shaders/sprite.frag</file> + <file>shaders/sprite.vert</file> + <file>shaders/sprite_core.frag</file> + <file>shaders/sprite_core.vert</file> </qresource> </RCC> diff --git a/src/quick/scenegraph/shaders/sprite.frag b/src/quick/scenegraph/shaders/sprite.frag new file mode 100644 index 0000000000..e1fcb0f006 --- /dev/null +++ b/src/quick/scenegraph/shaders/sprite.frag @@ -0,0 +1,12 @@ +uniform sampler2D _qt_texture; +uniform lowp float qt_Opacity; + +varying highp vec4 fTexS; +varying lowp float progress; + +void main() +{ + gl_FragColor = mix(texture2D(_qt_texture, fTexS.xy), + texture2D(_qt_texture, fTexS.zw), + progress) * qt_Opacity; +}
\ No newline at end of file diff --git a/src/quick/scenegraph/shaders/sprite.vert b/src/quick/scenegraph/shaders/sprite.vert new file mode 100644 index 0000000000..fc826f60b4 --- /dev/null +++ b/src/quick/scenegraph/shaders/sprite.vert @@ -0,0 +1,23 @@ +attribute highp vec2 vPos; +attribute highp vec2 vTex; + +uniform highp vec3 animData;// w,h(premultiplied of anim), interpolation progress +uniform highp vec4 animPos;//x,y, x,y (two frames for interpolation) + +uniform highp mat4 qt_Matrix; + +varying highp vec4 fTexS; +varying lowp float progress; + +void main() +{ + progress = animData.z; + + // Calculate frame location in texture + fTexS.xy = animPos.xy + vTex.xy * animData.xy; + + // Next frame is also passed, for interpolation + fTexS.zw = animPos.zw + vTex.xy * animData.xy; + + gl_Position = qt_Matrix * vec4(vPos.x, vPos.y, 0, 1); +}
\ No newline at end of file diff --git a/src/quick/scenegraph/shaders/sprite_core.frag b/src/quick/scenegraph/shaders/sprite_core.frag new file mode 100644 index 0000000000..c1087a8754 --- /dev/null +++ b/src/quick/scenegraph/shaders/sprite_core.frag @@ -0,0 +1,16 @@ +#version 150 core + +in vec4 fTexS; +in float progress; + +out vec4 fragColor; + +uniform sampler2D _qt_texture; +uniform float qt_Opacity; + +void main() +{ + fragColor = mix(texture(_qt_texture, fTexS.xy), + texture(_qt_texture, fTexS.zw), + progress) * qt_Opacity; +}
\ No newline at end of file diff --git a/src/quick/scenegraph/shaders/sprite_core.vert b/src/quick/scenegraph/shaders/sprite_core.vert new file mode 100644 index 0000000000..5027bf03fc --- /dev/null +++ b/src/quick/scenegraph/shaders/sprite_core.vert @@ -0,0 +1,24 @@ +#version 150 core + +in vec2 vPos; +in vec2 vTex; + +out vec4 fTexS; +out float progress; + +uniform vec3 animData; // w,h(premultiplied of anim), interpolation progress +uniform vec4 animPos; // x,y, x,y (two frames for interpolation) +uniform mat4 qt_Matrix; + +void main() +{ + progress = animData.z; + + // Calculate frame location in texture + fTexS.xy = animPos.xy + vTex.xy * animData.xy; + + // Next frame is also passed, for interpolation + fTexS.zw = animPos.zw + vTex.xy * animData.xy; + + gl_Position = qt_Matrix * vec4(vPos.x, vPos.y, 0, 1); +}
\ No newline at end of file diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp index 098a4a666b..40c3293c7b 100644 --- a/src/quick/scenegraph/util/qsgatlastexture.cpp +++ b/src/quick/scenegraph/util/qsgatlastexture.cpp @@ -158,13 +158,13 @@ Atlas::Atlas(const QSize &size) wrongfullyReportsBgra8888Support = false; const char *ext = (const char *) QOpenGLContext::currentContext()->functions()->glGetString(GL_EXTENSIONS); - if (!wrongfullyReportsBgra8888Support + if (ext && !wrongfullyReportsBgra8888Support && (strstr(ext, "GL_EXT_bgra") || strstr(ext, "GL_EXT_texture_format_BGRA8888") || strstr(ext, "GL_IMG_texture_format_BGRA8888"))) { m_internalFormat = m_externalFormat = GL_BGRA; #if defined(Q_OS_DARWIN) && !defined(Q_OS_OSX) - } else if (strstr(ext, "GL_APPLE_texture_format_BGRA8888")) { + } else if (ext && strstr(ext, "GL_APPLE_texture_format_BGRA8888")) { m_internalFormat = GL_RGBA; m_externalFormat = GL_BGRA; #endif // IOS || TVOS diff --git a/src/quick/scenegraph/util/qsgatlastexture_p.h b/src/quick/scenegraph/util/qsgatlastexture_p.h index cd24645fcf..3dee539547 100644 --- a/src/quick/scenegraph/util/qsgatlastexture_p.h +++ b/src/quick/scenegraph/util/qsgatlastexture_p.h @@ -131,26 +131,26 @@ public: Texture(Atlas *atlas, const QRect &textureRect, const QImage &image); ~Texture(); - int textureId() const { return m_atlas->textureId(); } - QSize textureSize() const { return atlasSubRectWithoutPadding().size(); } + int textureId() const override { return m_atlas->textureId(); } + QSize textureSize() const override { return atlasSubRectWithoutPadding().size(); } void setHasAlphaChannel(bool alpha) { m_has_alpha = alpha; } - bool hasAlphaChannel() const { return m_has_alpha; } - bool hasMipmaps() const { return false; } - bool isAtlasTexture() const { return true; } + bool hasAlphaChannel() const override { return m_has_alpha; } + bool hasMipmaps() const override { return false; } + bool isAtlasTexture() const override { return true; } - QRectF normalizedTextureSubRect() const { return m_texture_coords_rect; } + QRectF normalizedTextureSubRect() const override { return m_texture_coords_rect; } QRect atlasSubRect() const { return m_allocated_rect; } QRect atlasSubRectWithoutPadding() const { return m_allocated_rect.adjusted(1, 1, -1, -1); } bool isTexture() const { return true; } - QSGTexture *removedFromAtlas() const; + QSGTexture *removedFromAtlas() const override; void releaseImage() { m_image = QImage(); } const QImage &image() const { return m_image; } - void bind(); + void bind() override; private: QRect m_allocated_rect; diff --git a/src/quick/scenegraph/util/qsgdefaultimagenode.cpp b/src/quick/scenegraph/util/qsgdefaultimagenode.cpp new file mode 100644 index 0000000000..6afe591dca --- /dev/null +++ b/src/quick/scenegraph/util/qsgdefaultimagenode.cpp @@ -0,0 +1,205 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgdefaultimagenode_p.h" +#include <private/qsgnode_p.h> + +QT_BEGIN_NAMESPACE + +QSGDefaultImageNode::QSGDefaultImageNode() + : m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4) + , m_texCoordMode(QSGDefaultImageNode::NoTransform) + , m_isAtlasTexture(false) + , m_ownsTexture(false) +{ + setGeometry(&m_geometry); + setMaterial(&m_material); + setOpaqueMaterial(&m_opaque_material); + m_material.setMipmapFiltering(QSGTexture::None); + m_opaque_material.setMipmapFiltering(QSGTexture::None); +#ifdef QSG_RUNTIME_DESCRIPTION + qsgnode_set_description(this, QLatin1String("image")); +#endif +} + +QSGDefaultImageNode::~QSGDefaultImageNode() +{ + if (m_ownsTexture) + delete m_material.texture(); +} + +void QSGDefaultImageNode::setFiltering(QSGTexture::Filtering filtering) +{ + if (m_material.filtering() == filtering) + return; + + m_material.setFiltering(filtering); + m_opaque_material.setFiltering(filtering); + markDirty(DirtyMaterial); +} + +QSGTexture::Filtering QSGDefaultImageNode::filtering() const +{ + return m_material.filtering(); +} + +void QSGDefaultImageNode::setMipmapFiltering(QSGTexture::Filtering filtering) +{ + if (m_material.mipmapFiltering() == filtering) + return; + + m_material.setMipmapFiltering(filtering); + m_opaque_material.setMipmapFiltering(filtering); + markDirty(DirtyMaterial); +} + +QSGTexture::Filtering QSGDefaultImageNode::mipmapFiltering() const +{ + return m_material.mipmapFiltering(); +} + +void QSGDefaultImageNode::setRect(const QRectF &r) +{ + if (m_rect == r) + return; + + m_rect = r; + rebuildGeometry(&m_geometry, texture(), m_rect, m_sourceRect, m_texCoordMode); + markDirty(DirtyGeometry); +} + +QRectF QSGDefaultImageNode::rect() const +{ + return m_rect; +} + +void QSGDefaultImageNode::setSourceRect(const QRectF &r) +{ + if (m_sourceRect == r) + return; + + m_sourceRect = r; + rebuildGeometry(&m_geometry, texture(), m_rect, m_sourceRect, m_texCoordMode); + markDirty(DirtyGeometry); +} + +QRectF QSGDefaultImageNode::sourceRect() const +{ + return m_sourceRect; +} + +void QSGDefaultImageNode::setTexture(QSGTexture *texture) +{ + Q_ASSERT(texture); + if (m_ownsTexture) + delete m_material.texture(); + m_material.setTexture(texture); + m_opaque_material.setTexture(texture); + rebuildGeometry(&m_geometry, texture, m_rect, m_sourceRect, m_texCoordMode); + + DirtyState dirty = DirtyMaterial; + // It would be tempting to skip the extra bit here and instead use + // m_material.texture to get the old state, but that texture could + // have been deleted in the mean time. + bool wasAtlas = m_isAtlasTexture; + m_isAtlasTexture = texture->isAtlasTexture(); + if (wasAtlas || m_isAtlasTexture) + dirty |= DirtyGeometry; + markDirty(dirty); +} + +QSGTexture *QSGDefaultImageNode::texture() const +{ + return m_material.texture(); +} + +void QSGDefaultImageNode::setTextureCoordinatesTransform(TextureCoordinatesTransformMode mode) +{ + if (m_texCoordMode == mode) + return; + m_texCoordMode = mode; + rebuildGeometry(&m_geometry, texture(), m_rect, m_sourceRect, m_texCoordMode); + markDirty(DirtyMaterial); +} + +QSGDefaultImageNode::TextureCoordinatesTransformMode QSGDefaultImageNode::textureCoordinatesTransform() const +{ + return m_texCoordMode; +} + +void QSGDefaultImageNode::setOwnsTexture(bool owns) +{ + m_ownsTexture = owns; +} + +bool QSGDefaultImageNode::ownsTexture() const +{ + return m_ownsTexture; +} + +void QSGDefaultImageNode::rebuildGeometry(QSGGeometry *g, + QSGTexture *texture, + const QRectF &rect, + QRectF sourceRect, + TextureCoordinatesTransformMode texCoordMode) +{ + if (!texture) + return; + + if (!sourceRect.width() || !sourceRect.height()) { + QSize ts = texture->textureSize(); + sourceRect = QRectF(0, 0, ts.width(), ts.height()); + } + + // Maybe transform the texture coordinates + if (texCoordMode.testFlag(QSGImageNode::MirrorHorizontally)) { + float tmp = sourceRect.left(); + sourceRect.setLeft(sourceRect.right()); + sourceRect.setRight(tmp); + } + if (texCoordMode.testFlag(QSGImageNode::MirrorVertically)) { + float tmp = sourceRect.top(); + sourceRect.setTop(sourceRect.bottom()); + sourceRect.setBottom(tmp); + } + + QSGGeometry::updateTexturedRectGeometry(g, rect, texture->convertToNormalizedSourceRect(sourceRect)); +} + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgdefaultimagenode_p.h b/src/quick/scenegraph/util/qsgdefaultimagenode_p.h new file mode 100644 index 0000000000..eb6c487c18 --- /dev/null +++ b/src/quick/scenegraph/util/qsgdefaultimagenode_p.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGDEFAULTIMAGENODE_P_H +#define QSGDEFAULTIMAGENODE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt 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. +// + +#include <QtQuick/private/qtquickglobal_p.h> +#include <QtQuick/qsgimagenode.h> +#include <QtQuick/qsggeometry.h> +#include <QtQuick/qsgtexturematerial.h> + +QT_BEGIN_NAMESPACE + +class Q_QUICK_PRIVATE_EXPORT QSGDefaultImageNode : public QSGImageNode +{ +public: + QSGDefaultImageNode(); + ~QSGDefaultImageNode(); + + void setRect(const QRectF &rect) override; + QRectF rect() const override; + + void setSourceRect(const QRectF &r) override; + QRectF sourceRect() const override; + + void setTexture(QSGTexture *texture) override; + QSGTexture *texture() const override; + + void setFiltering(QSGTexture::Filtering filtering) override; + QSGTexture::Filtering filtering() const override; + + void setMipmapFiltering(QSGTexture::Filtering filtering) override; + QSGTexture::Filtering mipmapFiltering() const override; + + void setTextureCoordinatesTransform(TextureCoordinatesTransformMode mode) override; + TextureCoordinatesTransformMode textureCoordinatesTransform() const override; + + void setOwnsTexture(bool owns) override; + bool ownsTexture() const override; + + static void rebuildGeometry(QSGGeometry *g, + QSGTexture *texture, + const QRectF &rect, + QRectF sourceRect, + TextureCoordinatesTransformMode texCoordMode); + +private: + QSGGeometry m_geometry; + QSGOpaqueTextureMaterial m_opaque_material; + QSGTextureMaterial m_material; + QRectF m_rect; + QRectF m_sourceRect; + TextureCoordinatesTransformMode m_texCoordMode; + uint m_isAtlasTexture : 1; + uint m_ownsTexture : 1; +}; + +QT_END_NAMESPACE + +#endif // QSGDEFAULTIMAGENODE_P_H diff --git a/src/quick/scenegraph/util/qsgdefaultninepatchnode.cpp b/src/quick/scenegraph/util/qsgdefaultninepatchnode.cpp new file mode 100644 index 0000000000..e5a53a3617 --- /dev/null +++ b/src/quick/scenegraph/util/qsgdefaultninepatchnode.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgdefaultninepatchnode_p.h" + +QT_BEGIN_NAMESPACE + +QSGDefaultNinePatchNode::QSGDefaultNinePatchNode() + : m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4) +{ + m_geometry.setDrawingMode(QSGGeometry::DrawTriangleStrip); + setGeometry(&m_geometry); + setMaterial(&m_material); +} + +QSGDefaultNinePatchNode::~QSGDefaultNinePatchNode() +{ + delete m_material.texture(); +} + +void QSGDefaultNinePatchNode::setTexture(QSGTexture *texture) +{ + delete m_material.texture(); + m_material.setTexture(texture); +} + +void QSGDefaultNinePatchNode::setBounds(const QRectF &bounds) +{ + m_bounds = bounds; +} + +void QSGDefaultNinePatchNode::setDevicePixelRatio(qreal ratio) +{ + m_devicePixelRatio = ratio; +} + +void QSGDefaultNinePatchNode::setPadding(qreal left, qreal top, qreal right, qreal bottom) +{ + m_padding = QVector4D(left, top, right, bottom); +} + +void QSGDefaultNinePatchNode::update() +{ + rebuildGeometry(m_material.texture(), &m_geometry, m_padding, m_bounds, m_devicePixelRatio); + markDirty(QSGNode::DirtyGeometry | QSGNode::DirtyMaterial); +} + +void QSGDefaultNinePatchNode::rebuildGeometry(QSGTexture *texture, QSGGeometry *geometry, const QVector4D &padding, + const QRectF &bounds, qreal dpr) +{ + if (padding.x() <= 0 && padding.y() <= 0 && padding.z() <= 0 && padding.w() <= 0) { + geometry->allocate(4, 0); + QSGGeometry::updateTexturedRectGeometry(geometry, bounds, texture->normalizedTextureSubRect()); + return; + } + + QRectF tc = texture->normalizedTextureSubRect(); + QSize ts = texture->textureSize(); + ts.setHeight(ts.height() / dpr); + ts.setWidth(ts.width() / dpr); + + qreal invtw = tc.width() / ts.width(); + qreal invth = tc.height() / ts.height(); + + struct Coord { qreal p; qreal t; }; + Coord cx[4] = { { bounds.left(), tc.left() }, + { bounds.left() + padding.x(), tc.left() + padding.x() * invtw }, + { bounds.right() - padding.z(), tc.right() - padding.z() * invtw }, + { bounds.right(), tc.right() } + }; + Coord cy[4] = { { bounds.top(), tc.top() }, + { bounds.top() + padding.y(), tc.top() + padding.y() * invth }, + { bounds.bottom() - padding.w(), tc.bottom() - padding.w() * invth }, + { bounds.bottom(), tc.bottom() } + }; + + geometry->allocate(16, 28); + QSGGeometry::TexturedPoint2D *v = geometry->vertexDataAsTexturedPoint2D(); + for (int y = 0; y < 4; ++y) { + for (int x = 0; x < 4; ++x) { + v->set(cx[x].p, cy[y].p, cx[x].t, cy[y].t); + ++v; + } + } + + quint16 *i = geometry->indexDataAsUShort(); + for (int r = 0; r < 3; ++r) { + if (r > 0) + *i++ = 4 * r; + for (int c = 0; c < 4; ++c) { + i[0] = 4 * r + c; + i[1] = 4 * r + c + 4; + i += 2; + } + if (r < 2) + *i++ = 4 * r + 3 + 4; + } +} + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareninepatchnode_p.h b/src/quick/scenegraph/util/qsgdefaultninepatchnode_p.h index bc7aec1b5a..675cf48f47 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwareninepatchnode_p.h +++ b/src/quick/scenegraph/util/qsgdefaultninepatchnode_p.h @@ -37,10 +37,8 @@ ** ****************************************************************************/ -#ifndef QSGSOFTWARENINEPATCHNODE_H -#define QSGSOFTWARENINEPATCHNODE_H - -#include <private/qsgadaptationlayer_p.h> +#ifndef QSGDEFAULTNINEPATCHNODE_P_H +#define QSGDEFAULTNINEPATCHNODE_P_H // // W A R N I N G @@ -53,12 +51,18 @@ // We mean it. // +#include <private/qtquickglobal_p.h> +#include <QtQuick/qsgninepatchnode.h> +#include <QtQuick/qsggeometry.h> +#include <QtQuick/qsgtexturematerial.h> + QT_BEGIN_NAMESPACE -class QSGSoftwareNinePatchNode : public QSGNinePatchNode +class Q_QUICK_PRIVATE_EXPORT QSGDefaultNinePatchNode : public QSGNinePatchNode { public: - QSGSoftwareNinePatchNode(); + QSGDefaultNinePatchNode(); + ~QSGDefaultNinePatchNode(); void setTexture(QSGTexture *texture) override; void setBounds(const QRectF &bounds) override; @@ -66,17 +70,17 @@ public: void setPadding(qreal left, qreal top, qreal right, qreal bottom) override; void update() override; - void paint(QPainter *painter); - - QRectF bounds() const; + static void rebuildGeometry(QSGTexture *texture, QSGGeometry *geometry, const QVector4D &padding, + const QRectF &bounds, qreal dpr); private: - QPixmap m_pixmap; QRectF m_bounds; - qreal m_pixelRatio; - QMargins m_margins; + qreal m_devicePixelRatio; + QVector4D m_padding; + QSGGeometry m_geometry; + QSGTextureMaterial m_material; }; QT_END_NAMESPACE -#endif // QSGSOFTWARENINEPATCHNODE_H +#endif // QSGDEFAULTNINEPATCHNODE_P_H diff --git a/src/quick/scenegraph/util/qsgdefaultpainternode.cpp b/src/quick/scenegraph/util/qsgdefaultpainternode.cpp index 4dd60c76f5..e1aea290a3 100644 --- a/src/quick/scenegraph/util/qsgdefaultpainternode.cpp +++ b/src/quick/scenegraph/util/qsgdefaultpainternode.cpp @@ -225,7 +225,7 @@ void QSGDefaultPainterNode::updateGeometry() if (m_actualRenderTarget == QQuickPaintedItem::Image) source = QRectF(0, 0, 1, 1); else - source = QRectF(0, 0, qreal(m_size.width()) / m_fboSize.width(), qreal(m_size.height()) / m_fboSize.height()); + source = QRectF(0, 0, qreal(m_textureSize.width()) / m_fboSize.width(), qreal(m_textureSize.height()) / m_fboSize.height()); QRectF dest(0, 0, m_size.width(), m_size.height()); if (m_actualRenderTarget == QQuickPaintedItem::InvertedYFramebufferObject) dest = QRectF(QPointF(0, m_size.height()), QPointF(m_size.width(), 0)); @@ -307,7 +307,7 @@ void QSGDefaultPainterNode::updateRenderTarget() QSGPainterTexture *texture = new QSGPainterTexture; if (m_actualRenderTarget == QQuickPaintedItem::Image) { texture->setOwnsTexture(true); - texture->setTextureSize(m_size); + texture->setTextureSize(m_textureSize); } else { texture->setTextureId(m_fbo->texture()); texture->setOwnsTexture(false); @@ -317,7 +317,6 @@ void QSGDefaultPainterNode::updateRenderTarget() if (m_texture) delete m_texture; - texture->setTextureSize(m_size); m_texture = texture; } diff --git a/src/quick/scenegraph/util/qsgdefaultpainternode_p.h b/src/quick/scenegraph/util/qsgdefaultpainternode_p.h index 069ef155b1..a433b3292a 100644 --- a/src/quick/scenegraph/util/qsgdefaultpainternode_p.h +++ b/src/quick/scenegraph/util/qsgdefaultpainternode_p.h @@ -72,7 +72,7 @@ public: void setDirtyRect(const QRect &rect) { m_dirty_rect = rect; } - void bind(); + void bind() override; private: QRect m_dirty_rect; @@ -84,43 +84,43 @@ public: QSGDefaultPainterNode(QQuickPaintedItem *item); virtual ~QSGDefaultPainterNode(); - void setPreferredRenderTarget(QQuickPaintedItem::RenderTarget target); + void setPreferredRenderTarget(QQuickPaintedItem::RenderTarget target) override; - void setSize(const QSize &size); + void setSize(const QSize &size) override; QSize size() const { return m_size; } - void setDirty(const QRect &dirtyRect = QRect()); + void setDirty(const QRect &dirtyRect = QRect()) override; - void setOpaquePainting(bool opaque); + void setOpaquePainting(bool opaque) override; bool opaquePainting() const { return m_opaquePainting; } - void setLinearFiltering(bool linearFiltering); + void setLinearFiltering(bool linearFiltering) override; bool linearFiltering() const { return m_linear_filtering; } - void setMipmapping(bool mipmapping); + void setMipmapping(bool mipmapping) override; bool mipmapping() const { return m_mipmapping; } - void setSmoothPainting(bool s); + void setSmoothPainting(bool s) override; bool smoothPainting() const { return m_smoothPainting; } - void setFillColor(const QColor &c); + void setFillColor(const QColor &c) override; QColor fillColor() const { return m_fillColor; } - void setContentsScale(qreal s); + void setContentsScale(qreal s) override; qreal contentsScale() const { return m_contentsScale; } - void setFastFBOResizing(bool dynamic); + void setFastFBOResizing(bool dynamic) override; bool fastFBOResizing() const { return m_fastFBOResizing; } - void setTextureSize(const QSize &textureSize); + void setTextureSize(const QSize &textureSize) override; QSize textureSize() const { return m_textureSize; } - QImage toImage() const; - void update(); + QImage toImage() const override; + void update() override; void paint(); - QSGTexture *texture() const { return m_texture; } + QSGTexture *texture() const override { return m_texture; } private: void updateTexture(); diff --git a/src/quick/scenegraph/util/qsgdefaultrectanglenode.cpp b/src/quick/scenegraph/util/qsgdefaultrectanglenode.cpp new file mode 100644 index 0000000000..e1c8672add --- /dev/null +++ b/src/quick/scenegraph/util/qsgdefaultrectanglenode.cpp @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgdefaultrectanglenode_p.h" +#include "qsgflatcolormaterial.h" + +QT_BEGIN_NAMESPACE + +// Unlike our predecessor, QSGSimpleRectNode, use QSGVertexColorMaterial +// instead of Flat in order to allow better batching in the renderer. + +QSGDefaultRectangleNode::QSGDefaultRectangleNode() + : m_geometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), 4) +{ + QSGGeometry::updateColoredRectGeometry(&m_geometry, QRectF()); + setMaterial(&m_material); + setGeometry(&m_geometry); + setColor(QColor(255, 255, 255)); +#ifdef QSG_RUNTIME_DESCRIPTION + qsgnode_set_description(this, QLatin1String("rectangle")); +#endif +} + +void QSGDefaultRectangleNode::setRect(const QRectF &rect) +{ + QSGGeometry::updateColoredRectGeometry(&m_geometry, rect); + markDirty(QSGNode::DirtyGeometry); +} + +QRectF QSGDefaultRectangleNode::rect() const +{ + const QSGGeometry::ColoredPoint2D *pts = m_geometry.vertexDataAsColoredPoint2D(); + return QRectF(pts[0].x, + pts[0].y, + pts[3].x - pts[0].x, + pts[3].y - pts[0].y); +} + +void QSGDefaultRectangleNode::setColor(const QColor &color) +{ + if (color != m_color) { + m_color = color; + QSGGeometry::ColoredPoint2D *pts = m_geometry.vertexDataAsColoredPoint2D(); + for (int i = 0; i < 4; ++i) { + pts[i].r = uchar(qRound(m_color.redF() * m_color.alphaF() * 255)); + pts[i].g = uchar(qRound(m_color.greenF() * m_color.alphaF() * 255)); + pts[i].b = uchar(qRound(m_color.blueF() * m_color.alphaF() * 255)); + pts[i].a = uchar(qRound(m_color.alphaF() * 255)); + } + markDirty(QSGNode::DirtyGeometry); + } +} + +QColor QSGDefaultRectangleNode::color() const +{ + return m_color; +} + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgdefaultrectanglenode_p.h b/src/quick/scenegraph/util/qsgdefaultrectanglenode_p.h new file mode 100644 index 0000000000..965aa8dabb --- /dev/null +++ b/src/quick/scenegraph/util/qsgdefaultrectanglenode_p.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGDEFAULTRECTANGLENODE_P_H +#define QSGDEFAULTRECTANGLENODE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt 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. +// + +#include <QtGui/qcolor.h> +#include <QtQuick/qsgrectanglenode.h> +#include <QtQuick/qsgvertexcolormaterial.h> + +QT_BEGIN_NAMESPACE + +class QSGDefaultRectangleNode : public QSGRectangleNode +{ +public: + QSGDefaultRectangleNode(); + + void setRect(const QRectF &rect) override; + QRectF rect() const override; + + void setColor(const QColor &color) override; + QColor color() const override; + +private: + QSGVertexColorMaterial m_material; + QSGGeometry m_geometry; + QColor m_color; +}; + +QT_END_NAMESPACE + +#endif // QSGDEFAULTRECTANGLENODE_P_H diff --git a/src/quick/scenegraph/util/qsgdepthstencilbuffer_p.h b/src/quick/scenegraph/util/qsgdepthstencilbuffer_p.h index c2d0590532..f7c6923021 100644 --- a/src/quick/scenegraph/util/qsgdepthstencilbuffer_p.h +++ b/src/quick/scenegraph/util/qsgdepthstencilbuffer_p.h @@ -119,7 +119,7 @@ public: virtual ~QSGDefaultDepthStencilBuffer(); protected: - virtual void free(); + void free() override; }; diff --git a/src/quick/scenegraph/util/qsgengine.cpp b/src/quick/scenegraph/util/qsgengine.cpp index 26a3d66077..ad1fcfa470 100644 --- a/src/quick/scenegraph/util/qsgengine.cpp +++ b/src/quick/scenegraph/util/qsgengine.cpp @@ -115,23 +115,21 @@ QSGEngine::~QSGEngine() */ void QSGEngine::initialize(QOpenGLContext *context) { -#ifndef QT_NO_OPENGL Q_D(QSGEngine); - if (QOpenGLContext::currentContext() != context) { +#ifndef QT_NO_OPENGL + if (context && QOpenGLContext::currentContext() != context) { qWarning("WARNING: The context must be current before calling QSGEngine::initialize."); return; } - - auto openGLRenderContext = static_cast<QSGDefaultRenderContext *>(d->sgRenderContext.data()); - - if (openGLRenderContext != nullptr && !openGLRenderContext->isValid()) { - openGLRenderContext->setAttachToGLContext(false); - openGLRenderContext->initialize(context); - connect(context, &QOpenGLContext::aboutToBeDestroyed, this, &QSGEngine::invalidate); - } -#else - Q_UNUSED(context) #endif + if (d->sgRenderContext && !d->sgRenderContext->isValid()) { + d->sgRenderContext->setAttachToGraphicsContext(false); + d->sgRenderContext->initialize(context); +#ifndef QT_NO_OPENGL + if (context) + connect(context, &QOpenGLContext::aboutToBeDestroyed, this, &QSGEngine::invalidate); +#endif + } } /*! @@ -223,4 +221,45 @@ QSGRendererInterface *QSGEngine::rendererInterface() const : nullptr; } +/*! + Creates a simple rectangle node. When the scenegraph is not initialized, the return value is null. + + This is cross-backend alternative to constructing a QSGSimpleRectNode directly. + + \since 5.8 + \sa QSGRectangleNode + */ +QSGRectangleNode *QSGEngine::createRectangleNode() const +{ + Q_D(const QSGEngine); + return d->sgRenderContext->isValid() ? d->sgRenderContext->sceneGraphContext()->createRectangleNode() : nullptr; +} + +/*! + Creates a simple image node. When the scenegraph is not initialized, the return value is null. + + This is cross-backend alternative to constructing a QSGSimpleTextureNode directly. + + \since 5.8 + \sa QSGImageNode + */ + +QSGImageNode *QSGEngine::createImageNode() const +{ + Q_D(const QSGEngine); + return d->sgRenderContext->isValid() ? d->sgRenderContext->sceneGraphContext()->createImageNode() : nullptr; +} + +/*! + Creates a nine patch node. When the scenegraph is not initialized, the return value is null. + + \since 5.8 + */ + +QSGNinePatchNode *QSGEngine::createNinePatchNode() const +{ + Q_D(const QSGEngine); + return d->sgRenderContext->isValid() ? d->sgRenderContext->sceneGraphContext()->createNinePatchNode() : nullptr; +} + QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgengine.h b/src/quick/scenegraph/util/qsgengine.h index 9d27fb5525..3c8b61852e 100644 --- a/src/quick/scenegraph/util/qsgengine.h +++ b/src/quick/scenegraph/util/qsgengine.h @@ -50,6 +50,9 @@ class QSGAbstractRenderer; class QSGEnginePrivate; class QSGTexture; class QSGRendererInterface; +class QSGRectangleNode; +class QSGImageNode; +class QSGNinePatchNode; class Q_QUICK_EXPORT QSGEngine : public QObject { @@ -74,6 +77,9 @@ public: QSGTexture *createTextureFromImage(const QImage &image, CreateTextureOptions options = CreateTextureOption()) const; QSGTexture *createTextureFromId(uint id, const QSize &size, CreateTextureOptions options = CreateTextureOption()) const; QSGRendererInterface *rendererInterface() const; + QSGRectangleNode *createRectangleNode() const; + QSGImageNode *createImageNode() const; + QSGNinePatchNode *createNinePatchNode() const; }; QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgflatcolormaterial.cpp b/src/quick/scenegraph/util/qsgflatcolormaterial.cpp index 5d7817163e..2ce27275cd 100644 --- a/src/quick/scenegraph/util/qsgflatcolormaterial.cpp +++ b/src/quick/scenegraph/util/qsgflatcolormaterial.cpp @@ -57,9 +57,10 @@ public: private: virtual void initialize(); - +#ifndef QT_NO_OPENGL int m_matrix_id; int m_color_id; +#endif }; QSGMaterialType FlatColorMaterialShader::type; diff --git a/src/quick/scenegraph/util/qsgflatcolormaterial.h b/src/quick/scenegraph/util/qsgflatcolormaterial.h index 7f292a2a9b..4829ac3279 100644 --- a/src/quick/scenegraph/util/qsgflatcolormaterial.h +++ b/src/quick/scenegraph/util/qsgflatcolormaterial.h @@ -49,13 +49,13 @@ class Q_QUICK_EXPORT QSGFlatColorMaterial : public QSGMaterial { public: QSGFlatColorMaterial(); - virtual QSGMaterialType *type() const; - virtual QSGMaterialShader *createShader() const; + QSGMaterialType *type() const override; + QSGMaterialShader *createShader() const override; void setColor(const QColor &color); const QColor &color() const { return m_color; } - int compare(const QSGMaterial *other) const; + int compare(const QSGMaterial *other) const override; private: QColor m_color; diff --git a/src/quick/scenegraph/util/qsgimagenode.cpp b/src/quick/scenegraph/util/qsgimagenode.cpp new file mode 100644 index 0000000000..a78bfc1c66 --- /dev/null +++ b/src/quick/scenegraph/util/qsgimagenode.cpp @@ -0,0 +1,190 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgimagenode.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QSGImageNode + \brief The QSGImageNode class is provided for convenience to easily draw + textured content using the QML scene graph. + + \inmodule QtQuick + \since 5.8 + + \warning The image node class must have a texture before being + added to the scene graph to be rendered. + */ + +/*! + \fn void QSGImageNode::setRect(const QRectF &rect) + + Sets the target rect of this image node to \a rect. + */ + +/*! + \fn void QSGImageNode::setRect(qreal x, qreal y, qreal w, qreal h) + \overload + + Sets the rectangle of this image node to begin at (\a x, \a y) and have + width \a w and height \a h. + */ + +/*! + \fn QRectF QSGImageNode::rect() const + + Returns the target rect of this image node. + */ + +/*! + \fn void QSGImageNode::setSourceRect(const QRectF &rect) + + Sets the source rect of this image node to \a rect. + */ + +/*! + \fn void QSGImageNode::setSourceRect(qreal x, qreal y, qreal w, qreal h) + \overload + + Sets the rectangle of this image node to show its texture from (\a x, \a y) and + have width \a w and height \a h relatively to the QSGTexture::textureSize. + */ + +/*! + \fn QRectF QSGImageNode::sourceRect() const + + Returns the source rect of this image node. + */ + +/*! + \fn void QSGImageNode::setTexture(QSGTexture *texture) + + Sets the texture of this image node to \a texture. + + Use setOwnsTexture() to set whether the node should take + ownership of the texture. By default, the node does not + take ownership. + + \warning An image node must have a texture before being added to the + scenegraph to be rendered. + */ + +/*! + \fn QSGTexture *QSGImageNode::texture() const + + Returns the texture for this image node. + */ + +/*! + \fn void QSGImageNode::setFiltering(QSGTexture::Filtering filtering) + + Sets the filtering to be used for this image node to \a filtering. + + For smooth scaling, use QSGTexture::Linear. For normal scaling, use + QSGTexture::Nearest. + */ + +/*! + \fn QSGTexture::Filtering QSGImageNode::filtering() const + + Returns the filtering for this image node. + */ + +/*! + \fn void QSGImageNode::setMipmapFiltering(QSGTexture::Filtering filtering) + + Sets the mipmap filtering to be used for this image node to \a filtering. + + For smooth scaling between mip maps, use QSGTexture::Linear. + For normal scaling, use QSGTexture::Nearest. + */ + +/*! + \fn QSGTexture::Filtering QSGImageNode::mipmapFiltering() const + + Returns the mipmap filtering for this image node. + */ + +/*! + \enum QSGImageNode::TextureCoordinatesTransformFlag + + The TextureCoordinatesTransformFlag enum is used to specify the mode used + to generate texture coordinates for a textured quad. + + \value NoTransform Texture coordinates are oriented with window coordinates + i.e. with origin at top-left. + + \value MirrorHorizontally Texture coordinates are inverted in the horizontal axis with + respect to window coordinates + + \value MirrorVertically Texture coordinates are inverted in the vertical axis with + respect to window coordinates + */ + +/*! + \fn void QSGImageNode::setTextureCoordinatesTransform(TextureCoordinatesTransformMode mode) + + Sets the method used to generate texture coordinates to \a mode. This can + be used to obtain correct orientation of the texture. This is commonly + needed when using a third-party OpenGL library to render to texture as + OpenGL has an inverted y-axis relative to Qt Quick. + */ + +/*! + \fn QSGImageNode::TextureCoordinatesTransformMode textureCoordinatesTransform() const + + Returns the mode used to generate texture coordinates for this node. + */ + +/*! + \fn void QSGImageNode::setOwnsTexture(bool owns) + + Sets whether the node takes ownership of the texture to \a owns. + + By default, the node does not take ownership of the texture. + */ + +/*! + \fn bool QSGImageNode::ownsTexture() const + + \return \c true if the node takes ownership of the texture; otherwise \c false. + */ + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgimagenode.h b/src/quick/scenegraph/util/qsgimagenode.h new file mode 100644 index 0000000000..7eab42c4e6 --- /dev/null +++ b/src/quick/scenegraph/util/qsgimagenode.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGIMAGENODE_H +#define QSGIMAGENODE_H + +#include <QtQuick/qsgnode.h> +#include <QtQuick/qsgtexture.h> + +QT_BEGIN_NAMESPACE + +class Q_QUICK_EXPORT QSGImageNode : public QSGGeometryNode +{ +public: + virtual ~QSGImageNode() { } + + virtual void setRect(const QRectF &rect) = 0; + inline void setRect(qreal x, qreal y, qreal w, qreal h) { setRect(QRectF(x, y, w, h)); } + virtual QRectF rect() const = 0; + + virtual void setSourceRect(const QRectF &r) = 0; + inline void setSourceRect(qreal x, qreal y, qreal w, qreal h) { setSourceRect(QRectF(x, y, w, h)); } + virtual QRectF sourceRect() const = 0; + + virtual void setTexture(QSGTexture *texture) = 0; + virtual QSGTexture *texture() const = 0; + + virtual void setFiltering(QSGTexture::Filtering filtering) = 0; + virtual QSGTexture::Filtering filtering() const = 0; + + virtual void setMipmapFiltering(QSGTexture::Filtering filtering) = 0; + virtual QSGTexture::Filtering mipmapFiltering() const = 0; + + enum TextureCoordinatesTransformFlag { + NoTransform = 0x00, + MirrorHorizontally = 0x01, + MirrorVertically = 0x02 + }; + Q_DECLARE_FLAGS(TextureCoordinatesTransformMode, TextureCoordinatesTransformFlag) + + virtual void setTextureCoordinatesTransform(TextureCoordinatesTransformMode mode) = 0; + virtual TextureCoordinatesTransformMode textureCoordinatesTransform() const = 0; + + virtual void setOwnsTexture(bool owns) = 0; + virtual bool ownsTexture() const = 0; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QSGImageNode::TextureCoordinatesTransformMode) + +QT_END_NAMESPACE + +#endif // QSGIMAGENODE_H diff --git a/src/quick/scenegraph/util/qsgninepatchnode.cpp b/src/quick/scenegraph/util/qsgninepatchnode.cpp new file mode 100644 index 0000000000..9c167ca76f --- /dev/null +++ b/src/quick/scenegraph/util/qsgninepatchnode.cpp @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgninepatchnode.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QSGNinePatchNode + \inmodule QtQuick + \since 5.8 + \internal + */ + +/*! + \fn void QSGNinePatchNode::setTexture(QSGTexture *texture) + \internal + */ + +/*! + \fn void QSGNinePatchNode::setBounds(const QRectF &bounds) + \internal + */ + +/*! + \fn void QSGNinePatchNode::setDevicePixelRatio(qreal ratio) + \internal + */ + +/*! + \fn void QSGNinePatchNode::setPadding(qreal left, qreal top, qreal right, qreal bottom) + \internal + */ + + +/*! + \fn void QSGNinePatchNode::update() + \internal + */ + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgninepatchnode.h b/src/quick/scenegraph/util/qsgninepatchnode.h new file mode 100644 index 0000000000..8677a432ba --- /dev/null +++ b/src/quick/scenegraph/util/qsgninepatchnode.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGNINEPATCHNODE_H +#define QSGNINEPATCHNODE_H + +#include <QtQuick/qsgnode.h> +#include <QtQuick/qsgtexture.h> + +QT_BEGIN_NAMESPACE + +class Q_QUICK_EXPORT QSGNinePatchNode : public QSGGeometryNode +{ +public: + virtual ~QSGNinePatchNode() { } + + virtual void setTexture(QSGTexture *texture) = 0; + virtual void setBounds(const QRectF &bounds) = 0; + virtual void setDevicePixelRatio(qreal ratio) = 0; + virtual void setPadding(qreal left, qreal top, qreal right, qreal bottom) = 0; + virtual void update() = 0; +}; + +QT_END_NAMESPACE + +#endif // QSGNINEPATCHNODE_H diff --git a/src/quick/scenegraph/util/qsgrectanglenode.cpp b/src/quick/scenegraph/util/qsgrectanglenode.cpp new file mode 100644 index 0000000000..38c1f16a63 --- /dev/null +++ b/src/quick/scenegraph/util/qsgrectanglenode.cpp @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgrectanglenode.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QSGRectangleNode + + \brief The QSGRectangleNode class is a convenience class for drawing + solid filled rectangles using scenegraph. + \inmodule QtQuick + \since 5.8 + */ + +/*! + \fn void QSGRectangleNode::setRect(const QRectF &rect) + + Sets the rectangle of this rect node to \a rect. + */ + +/*! + \fn void QSGRectangleNode::setRect(qreal x, qreal y, qreal w, qreal h) + \overload + + Sets the rectangle of this rect node to begin at (\a x, \a y) and have + width \a w and height \a h. + */ + +/*! + \fn QRectF QSGRectangleNode::rect() const + + Returns the rectangle that this rect node covers. + */ + +/*! + \fn void QSGRectangleNode::setColor(const QColor &color) + + Sets the color of this rectangle to \a color. The default color will be + white. + */ + +/*! + \fn QColor QSGRectangleNode::color() const + + Returns the color of this rectangle. + */ + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgrectanglenode.h b/src/quick/scenegraph/util/qsgrectanglenode.h new file mode 100644 index 0000000000..8e0da1d9c7 --- /dev/null +++ b/src/quick/scenegraph/util/qsgrectanglenode.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGRECTANGLENODE_H +#define QSGRECTANGLENODE_H + +#include <QtQuick/qsgnode.h> + +QT_BEGIN_NAMESPACE + +class Q_QUICK_EXPORT QSGRectangleNode : public QSGGeometryNode +{ +public: + virtual ~QSGRectangleNode() { } + + virtual void setRect(const QRectF &rect) = 0; + inline void setRect(qreal x, qreal y, qreal w, qreal h) { setRect(QRectF(x, y, w, h)); } + virtual QRectF rect() const = 0; + + virtual void setColor(const QColor &color) = 0; + virtual QColor color() const = 0; +}; + +QT_END_NAMESPACE + +#endif // QSGRECTANGLENODE_H diff --git a/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp b/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp index caa296451e..25af1997a8 100644 --- a/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp +++ b/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp @@ -310,13 +310,10 @@ void QSGShaderSourceBuilder::addDefinition(const QByteArray &definition) const char *insertionPos = extensionPos ? extensionPos : (versionPos ? versionPos : input); // Construct a new shader string, inserting the definition - QByteArray newSource; - newSource.reserve(m_source.size() + definition.size() + 9); - newSource += QByteArray::fromRawData(input, insertionPos - input); - newSource += QByteArrayLiteral("#define ") + definition + QByteArrayLiteral("\n"); - newSource += QByteArray::fromRawData(insertionPos, m_source.size() - (insertionPos - input)); - - m_source = newSource; + QByteArray newSource = QByteArray::fromRawData(input, insertionPos - input) + + "#define " + definition + '\n' + + QByteArray::fromRawData(insertionPos, m_source.size() - (insertionPos - input)); + m_source = std::move(newSource); } void QSGShaderSourceBuilder::removeVersion() diff --git a/src/quick/scenegraph/util/qsgsimplematerial.h b/src/quick/scenegraph/util/qsgsimplematerial.h index d07a68e850..01f98767fd 100644 --- a/src/quick/scenegraph/util/qsgsimplematerial.h +++ b/src/quick/scenegraph/util/qsgsimplematerial.h @@ -149,8 +149,8 @@ public: { } - QSGMaterialShader *createShader() const { return m_func(); } - QSGMaterialType *type() const { return &m_type; } + QSGMaterialShader *createShader() const override { return m_func(); } + QSGMaterialType *type() const override { return &m_type; } State *state() { return &m_state; } const State *state() const { return &m_state; } diff --git a/src/quick/scenegraph/util/qsgsimplerectnode.cpp b/src/quick/scenegraph/util/qsgsimplerectnode.cpp index 3f6b8b0eec..28b177be84 100644 --- a/src/quick/scenegraph/util/qsgsimplerectnode.cpp +++ b/src/quick/scenegraph/util/qsgsimplerectnode.cpp @@ -49,6 +49,12 @@ QT_BEGIN_NAMESPACE solid filled rectangles using scenegraph. \inmodule QtQuick + \warning This utility class is only functional when running with the OpenGL + or software backends of the Qt Quick scenegraph. For a proper cross-platform + alternative prefer using QSGRectangleNode via + QQuickWindow::createRectangleNode() or QSGEngine::createRectangleNode(). + + \deprecated */ diff --git a/src/quick/scenegraph/util/qsgsimpletexturenode.cpp b/src/quick/scenegraph/util/qsgsimpletexturenode.cpp index 1208a6bc72..6ce37de7cb 100644 --- a/src/quick/scenegraph/util/qsgsimpletexturenode.cpp +++ b/src/quick/scenegraph/util/qsgsimpletexturenode.cpp @@ -97,6 +97,13 @@ static void qsgsimpletexturenode_update(QSGGeometry *g, \warning The simple texture node class must have a texture before being added to the scene graph to be rendered. + + \warning This utility class is only functional when running with the OpenGL + or software backends of the Qt Quick scenegraph. For a proper cross-platform + alternative prefer using QSGImageNode via + QQuickWindow::createImageNode() or QSGEngine::createImageNode(). + + \deprecated */ /*! diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp index 19403deb73..4cf339aeb8 100644 --- a/src/quick/scenegraph/util/qsgtexture.cpp +++ b/src/quick/scenegraph/util/qsgtexture.cpp @@ -70,7 +70,9 @@ #include <QHash> #endif +#ifndef QT_NO_OPENGL static QElapsedTimer qsg_renderer_timer; +#endif #ifndef QT_NO_DEBUG static const bool qsg_leak_check = !qEnvironmentVariableIsEmpty("QML_LEAK_CHECK"); @@ -84,11 +86,13 @@ static const bool qsg_leak_check = !qEnvironmentVariableIsEmpty("QML_LEAK_CHECK" QT_BEGIN_NAMESPACE +#ifndef QT_NO_OPENGL inline static bool isPowerOfTwo(int x) { // Assumption: x >= 1 return x == (x & -x); } +#endif QSGTexturePrivate::QSGTexturePrivate() : wrapChanged(false) diff --git a/src/quick/scenegraph/util/qsgtexture_p.h b/src/quick/scenegraph/util/qsgtexture_p.h index a0d7eb41e3..e09cbdbef1 100644 --- a/src/quick/scenegraph/util/qsgtexture_p.h +++ b/src/quick/scenegraph/util/qsgtexture_p.h @@ -87,19 +87,19 @@ public: bool ownsTexture() const { return m_owns_texture; } void setTextureId(int id); - int textureId() const; + int textureId() const override; void setTextureSize(const QSize &size) { m_texture_size = size; } - QSize textureSize() const { return m_texture_size; } + QSize textureSize() const override { return m_texture_size; } void setHasAlphaChannel(bool alpha) { m_has_alpha = alpha; } - bool hasAlphaChannel() const { return m_has_alpha; } + bool hasAlphaChannel() const override { return m_has_alpha; } - bool hasMipmaps() const { return mipmapFiltering() != QSGTexture::None; } + bool hasMipmaps() const override { return mipmapFiltering() != QSGTexture::None; } void setImage(const QImage &image); const QImage &image() { return m_image; } - virtual void bind(); + void bind() override; static QSGPlainTexture *fromImage(const QImage &image) { QSGPlainTexture *t = new QSGPlainTexture(); diff --git a/src/quick/scenegraph/util/qsgtexturematerial.cpp b/src/quick/scenegraph/util/qsgtexturematerial.cpp index 3db8163376..119828bc81 100644 --- a/src/quick/scenegraph/util/qsgtexturematerial.cpp +++ b/src/quick/scenegraph/util/qsgtexturematerial.cpp @@ -46,11 +46,13 @@ QT_BEGIN_NAMESPACE +#ifndef QT_NO_OPENGL inline static bool isPowerOfTwo(int x) { // Assumption: x >= 1 return x == (x & -x); } +#endif QSGMaterialType QSGOpaqueTextureMaterialShader::type; diff --git a/src/quick/scenegraph/util/qsgtexturematerial.h b/src/quick/scenegraph/util/qsgtexturematerial.h index 02b59108b3..dc87131773 100644 --- a/src/quick/scenegraph/util/qsgtexturematerial.h +++ b/src/quick/scenegraph/util/qsgtexturematerial.h @@ -50,9 +50,9 @@ class Q_QUICK_EXPORT QSGOpaqueTextureMaterial : public QSGMaterial public: QSGOpaqueTextureMaterial(); - virtual QSGMaterialType *type() const; - virtual QSGMaterialShader *createShader() const; - virtual int compare(const QSGMaterial *other) const; + QSGMaterialType *type() const override; + QSGMaterialShader *createShader() const override; + int compare(const QSGMaterial *other) const override; void setTexture(QSGTexture *texture); QSGTexture *texture() const { return m_texture; } @@ -84,8 +84,8 @@ protected: class Q_QUICK_EXPORT QSGTextureMaterial : public QSGOpaqueTextureMaterial { public: - virtual QSGMaterialType *type() const; - virtual QSGMaterialShader *createShader() const; + QSGMaterialType *type() const override; + QSGMaterialShader *createShader() const override; }; QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgtexturematerial_p.h b/src/quick/scenegraph/util/qsgtexturematerial_p.h index 75e5877a72..093d820801 100644 --- a/src/quick/scenegraph/util/qsgtexturematerial_p.h +++ b/src/quick/scenegraph/util/qsgtexturematerial_p.h @@ -61,13 +61,13 @@ class Q_QUICK_PRIVATE_EXPORT QSGOpaqueTextureMaterialShader : public QSGMaterial public: QSGOpaqueTextureMaterialShader(); - virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect); - virtual char const *const *attributeNames() const; + void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; + char const *const *attributeNames() const override; static QSGMaterialType type; protected: - virtual void initialize(); + void initialize() override; int m_matrix_id; }; @@ -77,8 +77,8 @@ class QSGTextureMaterialShader : public QSGOpaqueTextureMaterialShader public: QSGTextureMaterialShader(); - virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect); - virtual void initialize(); + void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; + void initialize() override; static QSGMaterialType type; diff --git a/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp b/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp index dedbc86385..847ec289d8 100644 --- a/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp +++ b/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp @@ -55,9 +55,10 @@ public: private: virtual void initialize(); - +#ifndef QT_NO_OPENGL int m_matrix_id; int m_opacity_id; +#endif }; QSGMaterialType QSGVertexColorMaterialShader::type; diff --git a/src/quick/scenegraph/util/qsgvertexcolormaterial.h b/src/quick/scenegraph/util/qsgvertexcolormaterial.h index 68f32d8af0..65cb642d92 100644 --- a/src/quick/scenegraph/util/qsgvertexcolormaterial.h +++ b/src/quick/scenegraph/util/qsgvertexcolormaterial.h @@ -49,11 +49,11 @@ class Q_QUICK_EXPORT QSGVertexColorMaterial : public QSGMaterial public: QSGVertexColorMaterial(); - int compare(const QSGMaterial *other) const; + int compare(const QSGMaterial *other) const override; protected: - virtual QSGMaterialType *type() const; - virtual QSGMaterialShader *createShader() const; + QSGMaterialType *type() const override; + QSGMaterialShader *createShader() const override; }; QT_END_NAMESPACE |