From 29c833d54f93bc3443e055d2f958589f03463057 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Mon, 5 Oct 2020 21:50:35 +0200 Subject: [PATCH] QmlDesigner: Implement different render path for Qt 6 When building with Qt 6 or if qmlpuppet_unifiedRenderPath is set in the environment we switch to a different render path. In this case we use QQuickWindow::grabWindow() and render the root item. No composition is done in the Qt Creator process anymore. This is a similar approach we already take for the 3D view. Performance is acceptable and we fix rendering issues related to effects and layers. Change-Id: Ic963eca047e0bf16ca3a099ec94658ae2af0fb63 Reviewed-by: Thomas Hartmann Reviewed-by: Miikka Heikkinen --- .../instances/nodeinstanceserver.cpp | 34 +++++--- .../qml2puppet/instances/nodeinstanceserver.h | 2 + .../instances/objectnodeinstance.cpp | 5 ++ .../qml2puppet/instances/objectnodeinstance.h | 2 + .../instances/qt5nodeinstanceclientproxy.cpp | 15 +++- .../instances/qt5nodeinstanceserver.cpp | 3 + .../instances/qt5rendernodeinstanceserver.cpp | 23 +++++- .../instances/quickitemnodeinstance.cpp | 79 ++++++++++++++++--- .../instances/quickitemnodeinstance.h | 8 ++ .../instances/servernodeinstance.cpp | 5 ++ .../qml2puppet/instances/servernodeinstance.h | 3 + 11 files changed, 155 insertions(+), 24 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp index 45d5fce845d..183f036bf73 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp @@ -72,22 +72,23 @@ #include #include +#include +#include #include -#include -#include -#include -#include -#include #include -#include +#include #include +#include +#include #include #include -#include -#include +#include +#include #include #include -#include +#include +#include +#include #include @@ -1461,4 +1462,19 @@ void NodeInstanceServer::disableTimer() m_timerMode = TimerMode::DisableTimer; } +void NodeInstanceServer::sheduleRootItemRender() +{ + QSharedPointer result = m_rootNodeInstance.createGrabResult(); + qint32 instanceId = m_rootNodeInstance.instanceId(); + + if (result) { + connect(result.data(), &QQuickItemGrabResult::ready, [this, result, instanceId] { + QVector imageVector; + ImageContainer container(instanceId, result->image(), instanceId); + imageVector.append(container); + nodeInstanceClient()->pixmapChanged(PixmapChangedCommand(imageVector)); + }); + } +} + } // namespace QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h index bd6349d29a1..d5726a31f6f 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h @@ -241,6 +241,8 @@ protected: ComponentCompletedCommand createComponentCompletedCommand(const QList &instanceList); ChangeSelectionCommand createChangeSelectionCommand(const QList &instanceList); + void sheduleRootItemRender(); + void addChangedProperty(const InstancePropertyPair &property); virtual void startRenderTimer(); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp index 5991e2b28e9..d69846d400a 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp @@ -908,6 +908,11 @@ QImage ObjectNodeInstance::renderPreviewImage(const QSize & /*previewImageSize*/ return QImage(); } +QSharedPointer ObjectNodeInstance::createGrabResult() const +{ + return {}; +} + QObject *ObjectNodeInstance::parent() const { if (!object()) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h index 3026ffefce1..29e7dc640b0 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h @@ -84,6 +84,8 @@ public: virtual QImage renderImage() const; virtual QImage renderPreviewImage(const QSize &previewImageSize) const; + virtual QSharedPointer createGrabResult() const; + virtual QObject *parent() const; Pointer parentInstance() const; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp index defbf5614a3..64b6eb409c8 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp @@ -33,6 +33,7 @@ #include "qt5previewnodeinstanceserver.h" #include "qt5rendernodeinstanceserver.h" #include "qt5testnodeinstanceserver.h" +#include "quickitemnodeinstance.h" #include @@ -56,7 +57,19 @@ Qt5NodeInstanceClientProxy::Qt5NodeInstanceClientProxy(QObject *parent) : NodeInstanceClientProxy(parent) { prioritizeDown(); - DesignerSupport::activateDesignerWindowManager(); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + const bool qt6 = false; +#else + const bool qt6 = true; +#endif + + const bool unifiedRenderPath = qt6 || qEnvironmentVariableIsSet("QMLPUPPET_UNIFIED_RENDER_PATH"); + + if (unifiedRenderPath) + Internal::QuickItemNodeInstance::enableUnifiedRenderPath(true); + else + DesignerSupport::activateDesignerWindowManager(); + if (QCoreApplication::arguments().at(1) == QLatin1String("--readcapturedstream")) { qputenv("DESIGNER_DONT_USE_SHARED_MEMORY", "1"); setNodeInstanceServer(std::make_unique(this)); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp index 8a4b086aa55..c2015299c52 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp @@ -64,6 +64,8 @@ void Qt5NodeInstanceServer::initializeView() m_quickView = new QQuickView; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + /* enables grab window without show */ QSurfaceFormat surfaceFormat = m_quickView->requestedFormat(); surfaceFormat.setVersion(4, 1); surfaceFormat.setProfile(QSurfaceFormat::CoreProfile); @@ -72,6 +74,7 @@ void Qt5NodeInstanceServer::initializeView() m_quickView->setFormat(surfaceFormat); DesignerSupport::createOpenGLContext(m_quickView.data()); +#endif if (qEnvironmentVariableIsSet("QML_FILE_SELECTORS")) { QQmlFileSelector *fileSelector = new QQmlFileSelector(engine(), engine()); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp index 08b20ccd223..fd3446f3968 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp @@ -87,17 +87,27 @@ void Qt5RenderNodeInstanceServer::collectItemChangesAndSendChangeCommands() if (ancestorInstance.isValid()) m_dirtyInstanceSet.insert(ancestorInstance); } - DesignerSupport::updateDirtyNode(item); + Internal::QuickItemNodeInstance::updateDirtyNode(item); } } clearChangedPropertyList(); - if (!m_dirtyInstanceSet.isEmpty()) { - nodeInstanceClient()->pixmapChanged(createPixmapChangedCommand(QtHelpers::toList(m_dirtyInstanceSet))); - m_dirtyInstanceSet.clear(); + if (Internal::QuickItemNodeInstance::unifiedRenderPath()) { + /* QQuickItem::grabToImage render path */ + /* TODO implement QQuickItem::grabToImage based rendering */ + /* sheduleRootItemRender(); */ + nodeInstanceClient()->pixmapChanged(createPixmapChangedCommand({rootNodeInstance()})); + } else { + if (!m_dirtyInstanceSet.isEmpty()) { + nodeInstanceClient()->pixmapChanged( + createPixmapChangedCommand(QtHelpers::toList(m_dirtyInstanceSet))); + m_dirtyInstanceSet.clear(); + } } + m_dirtyInstanceSet.clear(); + resetAllItems(); slowDownRenderTimer(); @@ -137,6 +147,11 @@ void Qt5RenderNodeInstanceServer::createScene(const CreateSceneCommand &command) } nodeInstanceClient()->pixmapChanged(createPixmapChangedCommand(instanceList)); + +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) +#else + quickView()->show(); +#endif } void Qt5RenderNodeInstanceServer::clearScene(const ClearSceneCommand &command) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp index 6e67d58b925..bfaff0eea86 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp @@ -41,6 +41,7 @@ namespace QmlDesigner { namespace Internal { bool QuickItemNodeInstance::s_createEffectItem = false; +bool QuickItemNodeInstance::s_unifiedRenderPath = false; QuickItemNodeInstance::QuickItemNodeInstance(QQuickItem *item) : ObjectNodeInstance(item), @@ -58,7 +59,7 @@ QuickItemNodeInstance::QuickItemNodeInstance(QQuickItem *item) QuickItemNodeInstance::~QuickItemNodeInstance() { - if (quickItem()) + if (quickItem() && checkIfRefFromEffect(instanceId())) designerSupport()->derefFromEffectItem(quickItem()); } @@ -156,6 +157,19 @@ void QuickItemNodeInstance::createEffectItem(bool createEffectItem) s_createEffectItem = createEffectItem; } +void QuickItemNodeInstance::enableUnifiedRenderPath(bool unifiedRenderPath) +{ + s_unifiedRenderPath = unifiedRenderPath; +} + +bool QuickItemNodeInstance::checkIfRefFromEffect(qint32 id) +{ + if (s_unifiedRenderPath) + return false; + + return (s_createEffectItem || id == 0); +} + void QuickItemNodeInstance::initialize(const ObjectNodeInstance::Pointer &objectNodeInstance, InstanceContainer::NodeFlags flags) { @@ -166,10 +180,10 @@ void QuickItemNodeInstance::initialize(const ObjectNodeInstance::Pointer &object quickItem()->setParentItem(qobject_cast(nodeInstanceServer()->quickView()->rootObject())); } - if (quickItem()->window()) { - if (s_createEffectItem || instanceId() == 0) - designerSupport()->refFromEffectItem(quickItem(), - !flags.testFlag(InstanceContainer::ParentTakesOverRendering)); + if (quickItem()->window() && checkIfRefFromEffect(instanceId())) { + designerSupport()->refFromEffectItem(quickItem(), + !flags.testFlag( + InstanceContainer::ParentTakesOverRendering)); } ObjectNodeInstance::initialize(objectNodeInstance, flags); @@ -246,6 +260,20 @@ QStringList QuickItemNodeInstance::allStates() const return list; } +void QuickItemNodeInstance::updateDirtyNode(QQuickItem *item) +{ + if (s_unifiedRenderPath) { + item->update(); + return; + } + DesignerSupport::updateDirtyNode(item); +} + +bool QuickItemNodeInstance::unifiedRenderPath() +{ + return s_unifiedRenderPath; +} + QRectF QuickItemNodeInstance::contentItemBoundingBox() const { if (contentItem()) { @@ -378,6 +406,9 @@ double QuickItemNodeInstance::y() const QImage QuickItemNodeInstance::renderImage() const { + if (s_unifiedRenderPath && !isRootNodeInstance()) + return {}; + updateDirtyNodesRecursive(quickItem()); QRectF renderBoundingRect = boundingRect(); @@ -390,7 +421,16 @@ QImage QuickItemNodeInstance::renderImage() const nodeInstanceServer()->quickView()->beforeSynchronizing(); nodeInstanceServer()->quickView()->beforeRendering(); - QImage renderImage = designerSupport()->renderImageForItem(quickItem(), renderBoundingRect, size); + QImage renderImage; + +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + if (s_unifiedRenderPath) + renderImage = nodeInstanceServer()->quickView()->grabWindow(); + else + renderImage = designerSupport()->renderImageForItem(quickItem(), renderBoundingRect, size); +#else + renderImage = nodeInstanceServer()->quickView()->grabWindow(); +#endif nodeInstanceServer()->quickView()->afterRendering(); @@ -411,7 +451,20 @@ QImage QuickItemNodeInstance::renderPreviewImage(const QSize &previewImageSize) nodeInstanceServer()->quickView()->beforeSynchronizing(); nodeInstanceServer()->quickView()->beforeRendering(); - QImage image = designerSupport()->renderImageForItem(quickItem(), previewItemBoundingRect, size); + QImage image; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + if (s_unifiedRenderPath) + image = nodeInstanceServer()->quickView()->grabWindow(); + else + image = designerSupport()->renderImageForItem(quickItem(), + previewItemBoundingRect, + size); + +#else + image = nodeInstanceServer()->quickView()->grabWindow(); +#endif + + image = image.scaledToWidth(size.width()); nodeInstanceServer()->quickView()->afterRendering(); @@ -426,6 +479,11 @@ QImage QuickItemNodeInstance::renderPreviewImage(const QSize &previewImageSize) return QImage(); } +QSharedPointer QuickItemNodeInstance::createGrabResult() const +{ + return quickItem()->grabToImage(size().toSize()); +} + void QuickItemNodeInstance::updateAllDirtyNodesRecursive() { updateAllDirtyNodesRecursive(quickItem()); @@ -490,10 +548,11 @@ void QuickItemNodeInstance::updateDirtyNodesRecursive(QQuickItem *parentItem) co void QuickItemNodeInstance::updateAllDirtyNodesRecursive(QQuickItem *parentItem) const { - foreach (QQuickItem *childItem, parentItem->childItems()) - updateAllDirtyNodesRecursive(childItem); + const QList children = parentItem->childItems(); + for (QQuickItem *childItem : children) + updateAllDirtyNodesRecursive(childItem); - DesignerSupport::updateDirtyNode(parentItem); + updateDirtyNode(parentItem); } static inline bool isRectangleSane(const QRectF &rect) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.h index f42e45a8ff5..2c68fe79740 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.h @@ -45,6 +45,7 @@ public: static Pointer create(QObject *objectToBeWrapped); static void createEffectItem(bool createEffectItem); + static void enableUnifiedRenderPath(bool createEffectItem); void initialize(const ObjectNodeInstance::Pointer &objectNodeInstance, InstanceContainer::NodeFlags flags) override; @@ -70,6 +71,8 @@ public: QImage renderImage() const override; QImage renderPreviewImage(const QSize &previewImageSize) const override; + QSharedPointer createGrabResult() const override; + void updateAllDirtyNodesRecursive() override; @@ -98,6 +101,9 @@ public: QList allItemsRecursive() const override; QStringList allStates() const override; + static void updateDirtyNode(QQuickItem *item); + static bool unifiedRenderPath(); + protected: explicit QuickItemNodeInstance(QQuickItem*); QQuickItem *quickItem() const; @@ -118,6 +124,7 @@ protected: double x() const; double y() const; + bool checkIfRefFromEffect(qint32 id); private: //variables QPointer m_contentItem; @@ -131,6 +138,7 @@ private: //variables double m_width; double m_height; static bool s_createEffectItem; + static bool s_unifiedRenderPath; }; } // namespace Internal diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp index 69c854f3e99..511a89b62b2 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp @@ -120,6 +120,11 @@ QImage ServerNodeInstance::renderPreviewImage(const QSize &previewImageSize) con return m_nodeInstance->renderPreviewImage(previewImageSize); } +QSharedPointer ServerNodeInstance::createGrabResult() const +{ + return m_nodeInstance->createGrabResult(); +} + bool ServerNodeInstance::isRootNodeInstance() const { return isValid() && m_nodeInstance->isRootNodeInstance(); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h index 975d0e8c378..9150b2bd4ec 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h @@ -40,6 +40,7 @@ class QGraphicsItem; class QGraphicsTransform; #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) class QQuickItem; +class QQuickItemGrabResult; #endif QT_END_NAMESPACE @@ -102,6 +103,8 @@ public: QImage renderImage() const; QImage renderPreviewImage(const QSize &previewImageSize) const; + QSharedPointer createGrabResult() const; + ServerNodeInstance parent() const; bool hasParent() const;