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 <thomas.hartmann@qt.io>
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
This commit is contained in:
Thomas Hartmann
2020-10-05 21:50:35 +02:00
parent 2fe99cef9f
commit 29c833d54f
11 changed files with 155 additions and 24 deletions

View File

@@ -72,22 +72,23 @@
#include <requestmodelnodepreviewimagecommand.h> #include <requestmodelnodepreviewimagecommand.h>
#include <changelanguagecommand.h> #include <changelanguagecommand.h>
#include <designersupportdelegate.h>
#include <QAbstractAnimation>
#include <QDebug> #include <QDebug>
#include <QQmlEngine>
#include <QQmlApplicationEngine>
#include <QFileSystemWatcher>
#include <QUrl>
#include <QSet>
#include <QDir> #include <QDir>
#include <QVariant> #include <QFileSystemWatcher>
#include <QMetaType> #include <QMetaType>
#include <QMutableVectorIterator>
#include <QQmlApplicationEngine>
#include <QQmlComponent> #include <QQmlComponent>
#include <QQmlContext> #include <QQmlContext>
#include <qqmllist.h> #include <QQmlEngine>
#include <QAbstractAnimation> #include <QQuickItemGrabResult>
#include <QQuickView> #include <QQuickView>
#include <QSet> #include <QSet>
#include <designersupportdelegate.h> #include <QUrl>
#include <QVariant>
#include <qqmllist.h>
#include <algorithm> #include <algorithm>
@@ -1461,4 +1462,19 @@ void NodeInstanceServer::disableTimer()
m_timerMode = TimerMode::DisableTimer; m_timerMode = TimerMode::DisableTimer;
} }
void NodeInstanceServer::sheduleRootItemRender()
{
QSharedPointer<QQuickItemGrabResult> result = m_rootNodeInstance.createGrabResult();
qint32 instanceId = m_rootNodeInstance.instanceId();
if (result) {
connect(result.data(), &QQuickItemGrabResult::ready, [this, result, instanceId] {
QVector<ImageContainer> imageVector;
ImageContainer container(instanceId, result->image(), instanceId);
imageVector.append(container);
nodeInstanceClient()->pixmapChanged(PixmapChangedCommand(imageVector));
});
}
}
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -241,6 +241,8 @@ protected:
ComponentCompletedCommand createComponentCompletedCommand(const QList<ServerNodeInstance> &instanceList); ComponentCompletedCommand createComponentCompletedCommand(const QList<ServerNodeInstance> &instanceList);
ChangeSelectionCommand createChangeSelectionCommand(const QList<ServerNodeInstance> &instanceList); ChangeSelectionCommand createChangeSelectionCommand(const QList<ServerNodeInstance> &instanceList);
void sheduleRootItemRender();
void addChangedProperty(const InstancePropertyPair &property); void addChangedProperty(const InstancePropertyPair &property);
virtual void startRenderTimer(); virtual void startRenderTimer();

View File

@@ -908,6 +908,11 @@ QImage ObjectNodeInstance::renderPreviewImage(const QSize & /*previewImageSize*/
return QImage(); return QImage();
} }
QSharedPointer<QQuickItemGrabResult> ObjectNodeInstance::createGrabResult() const
{
return {};
}
QObject *ObjectNodeInstance::parent() const QObject *ObjectNodeInstance::parent() const
{ {
if (!object()) if (!object())

View File

@@ -84,6 +84,8 @@ public:
virtual QImage renderImage() const; virtual QImage renderImage() const;
virtual QImage renderPreviewImage(const QSize &previewImageSize) const; virtual QImage renderPreviewImage(const QSize &previewImageSize) const;
virtual QSharedPointer<QQuickItemGrabResult> createGrabResult() const;
virtual QObject *parent() const; virtual QObject *parent() const;
Pointer parentInstance() const; Pointer parentInstance() const;

View File

@@ -33,6 +33,7 @@
#include "qt5previewnodeinstanceserver.h" #include "qt5previewnodeinstanceserver.h"
#include "qt5rendernodeinstanceserver.h" #include "qt5rendernodeinstanceserver.h"
#include "qt5testnodeinstanceserver.h" #include "qt5testnodeinstanceserver.h"
#include "quickitemnodeinstance.h"
#include <designersupportdelegate.h> #include <designersupportdelegate.h>
@@ -56,7 +57,19 @@ Qt5NodeInstanceClientProxy::Qt5NodeInstanceClientProxy(QObject *parent) :
NodeInstanceClientProxy(parent) NodeInstanceClientProxy(parent)
{ {
prioritizeDown(); prioritizeDown();
#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(); DesignerSupport::activateDesignerWindowManager();
if (QCoreApplication::arguments().at(1) == QLatin1String("--readcapturedstream")) { if (QCoreApplication::arguments().at(1) == QLatin1String("--readcapturedstream")) {
qputenv("DESIGNER_DONT_USE_SHARED_MEMORY", "1"); qputenv("DESIGNER_DONT_USE_SHARED_MEMORY", "1");
setNodeInstanceServer(std::make_unique<Qt5TestNodeInstanceServer>(this)); setNodeInstanceServer(std::make_unique<Qt5TestNodeInstanceServer>(this));

View File

@@ -64,6 +64,8 @@ void Qt5NodeInstanceServer::initializeView()
m_quickView = new QQuickView; m_quickView = new QQuickView;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
/* enables grab window without show */
QSurfaceFormat surfaceFormat = m_quickView->requestedFormat(); QSurfaceFormat surfaceFormat = m_quickView->requestedFormat();
surfaceFormat.setVersion(4, 1); surfaceFormat.setVersion(4, 1);
surfaceFormat.setProfile(QSurfaceFormat::CoreProfile); surfaceFormat.setProfile(QSurfaceFormat::CoreProfile);
@@ -72,6 +74,7 @@ void Qt5NodeInstanceServer::initializeView()
m_quickView->setFormat(surfaceFormat); m_quickView->setFormat(surfaceFormat);
DesignerSupport::createOpenGLContext(m_quickView.data()); DesignerSupport::createOpenGLContext(m_quickView.data());
#endif
if (qEnvironmentVariableIsSet("QML_FILE_SELECTORS")) { if (qEnvironmentVariableIsSet("QML_FILE_SELECTORS")) {
QQmlFileSelector *fileSelector = new QQmlFileSelector(engine(), engine()); QQmlFileSelector *fileSelector = new QQmlFileSelector(engine(), engine());

View File

@@ -87,16 +87,26 @@ void Qt5RenderNodeInstanceServer::collectItemChangesAndSendChangeCommands()
if (ancestorInstance.isValid()) if (ancestorInstance.isValid())
m_dirtyInstanceSet.insert(ancestorInstance); m_dirtyInstanceSet.insert(ancestorInstance);
} }
DesignerSupport::updateDirtyNode(item); Internal::QuickItemNodeInstance::updateDirtyNode(item);
} }
} }
clearChangedPropertyList(); clearChangedPropertyList();
if (Internal::QuickItemNodeInstance::unifiedRenderPath()) {
/* QQuickItem::grabToImage render path */
/* TODO implement QQuickItem::grabToImage based rendering */
/* sheduleRootItemRender(); */
nodeInstanceClient()->pixmapChanged(createPixmapChangedCommand({rootNodeInstance()}));
} else {
if (!m_dirtyInstanceSet.isEmpty()) { if (!m_dirtyInstanceSet.isEmpty()) {
nodeInstanceClient()->pixmapChanged(createPixmapChangedCommand(QtHelpers::toList(m_dirtyInstanceSet))); nodeInstanceClient()->pixmapChanged(
createPixmapChangedCommand(QtHelpers::toList(m_dirtyInstanceSet)));
m_dirtyInstanceSet.clear(); m_dirtyInstanceSet.clear();
} }
}
m_dirtyInstanceSet.clear();
resetAllItems(); resetAllItems();
@@ -137,6 +147,11 @@ void Qt5RenderNodeInstanceServer::createScene(const CreateSceneCommand &command)
} }
nodeInstanceClient()->pixmapChanged(createPixmapChangedCommand(instanceList)); nodeInstanceClient()->pixmapChanged(createPixmapChangedCommand(instanceList));
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
#else
quickView()->show();
#endif
} }
void Qt5RenderNodeInstanceServer::clearScene(const ClearSceneCommand &command) void Qt5RenderNodeInstanceServer::clearScene(const ClearSceneCommand &command)

View File

@@ -41,6 +41,7 @@ namespace QmlDesigner {
namespace Internal { namespace Internal {
bool QuickItemNodeInstance::s_createEffectItem = false; bool QuickItemNodeInstance::s_createEffectItem = false;
bool QuickItemNodeInstance::s_unifiedRenderPath = false;
QuickItemNodeInstance::QuickItemNodeInstance(QQuickItem *item) QuickItemNodeInstance::QuickItemNodeInstance(QQuickItem *item)
: ObjectNodeInstance(item), : ObjectNodeInstance(item),
@@ -58,7 +59,7 @@ QuickItemNodeInstance::QuickItemNodeInstance(QQuickItem *item)
QuickItemNodeInstance::~QuickItemNodeInstance() QuickItemNodeInstance::~QuickItemNodeInstance()
{ {
if (quickItem()) if (quickItem() && checkIfRefFromEffect(instanceId()))
designerSupport()->derefFromEffectItem(quickItem()); designerSupport()->derefFromEffectItem(quickItem());
} }
@@ -156,6 +157,19 @@ void QuickItemNodeInstance::createEffectItem(bool createEffectItem)
s_createEffectItem = 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, void QuickItemNodeInstance::initialize(const ObjectNodeInstance::Pointer &objectNodeInstance,
InstanceContainer::NodeFlags flags) InstanceContainer::NodeFlags flags)
{ {
@@ -166,10 +180,10 @@ void QuickItemNodeInstance::initialize(const ObjectNodeInstance::Pointer &object
quickItem()->setParentItem(qobject_cast<QQuickItem*>(nodeInstanceServer()->quickView()->rootObject())); quickItem()->setParentItem(qobject_cast<QQuickItem*>(nodeInstanceServer()->quickView()->rootObject()));
} }
if (quickItem()->window()) { if (quickItem()->window() && checkIfRefFromEffect(instanceId())) {
if (s_createEffectItem || instanceId() == 0)
designerSupport()->refFromEffectItem(quickItem(), designerSupport()->refFromEffectItem(quickItem(),
!flags.testFlag(InstanceContainer::ParentTakesOverRendering)); !flags.testFlag(
InstanceContainer::ParentTakesOverRendering));
} }
ObjectNodeInstance::initialize(objectNodeInstance, flags); ObjectNodeInstance::initialize(objectNodeInstance, flags);
@@ -246,6 +260,20 @@ QStringList QuickItemNodeInstance::allStates() const
return list; 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 QRectF QuickItemNodeInstance::contentItemBoundingBox() const
{ {
if (contentItem()) { if (contentItem()) {
@@ -378,6 +406,9 @@ double QuickItemNodeInstance::y() const
QImage QuickItemNodeInstance::renderImage() const QImage QuickItemNodeInstance::renderImage() const
{ {
if (s_unifiedRenderPath && !isRootNodeInstance())
return {};
updateDirtyNodesRecursive(quickItem()); updateDirtyNodesRecursive(quickItem());
QRectF renderBoundingRect = boundingRect(); QRectF renderBoundingRect = boundingRect();
@@ -390,7 +421,16 @@ QImage QuickItemNodeInstance::renderImage() const
nodeInstanceServer()->quickView()->beforeSynchronizing(); nodeInstanceServer()->quickView()->beforeSynchronizing();
nodeInstanceServer()->quickView()->beforeRendering(); 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(); nodeInstanceServer()->quickView()->afterRendering();
@@ -411,7 +451,20 @@ QImage QuickItemNodeInstance::renderPreviewImage(const QSize &previewImageSize)
nodeInstanceServer()->quickView()->beforeSynchronizing(); nodeInstanceServer()->quickView()->beforeSynchronizing();
nodeInstanceServer()->quickView()->beforeRendering(); 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(); nodeInstanceServer()->quickView()->afterRendering();
@@ -426,6 +479,11 @@ QImage QuickItemNodeInstance::renderPreviewImage(const QSize &previewImageSize)
return QImage(); return QImage();
} }
QSharedPointer<QQuickItemGrabResult> QuickItemNodeInstance::createGrabResult() const
{
return quickItem()->grabToImage(size().toSize());
}
void QuickItemNodeInstance::updateAllDirtyNodesRecursive() void QuickItemNodeInstance::updateAllDirtyNodesRecursive()
{ {
updateAllDirtyNodesRecursive(quickItem()); updateAllDirtyNodesRecursive(quickItem());
@@ -490,10 +548,11 @@ void QuickItemNodeInstance::updateDirtyNodesRecursive(QQuickItem *parentItem) co
void QuickItemNodeInstance::updateAllDirtyNodesRecursive(QQuickItem *parentItem) const void QuickItemNodeInstance::updateAllDirtyNodesRecursive(QQuickItem *parentItem) const
{ {
foreach (QQuickItem *childItem, parentItem->childItems()) const QList<QQuickItem *> children = parentItem->childItems();
for (QQuickItem *childItem : children)
updateAllDirtyNodesRecursive(childItem); updateAllDirtyNodesRecursive(childItem);
DesignerSupport::updateDirtyNode(parentItem); updateDirtyNode(parentItem);
} }
static inline bool isRectangleSane(const QRectF &rect) static inline bool isRectangleSane(const QRectF &rect)

View File

@@ -45,6 +45,7 @@ public:
static Pointer create(QObject *objectToBeWrapped); static Pointer create(QObject *objectToBeWrapped);
static void createEffectItem(bool createEffectItem); static void createEffectItem(bool createEffectItem);
static void enableUnifiedRenderPath(bool createEffectItem);
void initialize(const ObjectNodeInstance::Pointer &objectNodeInstance, void initialize(const ObjectNodeInstance::Pointer &objectNodeInstance,
InstanceContainer::NodeFlags flags) override; InstanceContainer::NodeFlags flags) override;
@@ -70,6 +71,8 @@ public:
QImage renderImage() const override; QImage renderImage() const override;
QImage renderPreviewImage(const QSize &previewImageSize) const override; QImage renderPreviewImage(const QSize &previewImageSize) const override;
QSharedPointer<QQuickItemGrabResult> createGrabResult() const override;
void updateAllDirtyNodesRecursive() override; void updateAllDirtyNodesRecursive() override;
@@ -98,6 +101,9 @@ public:
QList<QQuickItem*> allItemsRecursive() const override; QList<QQuickItem*> allItemsRecursive() const override;
QStringList allStates() const override; QStringList allStates() const override;
static void updateDirtyNode(QQuickItem *item);
static bool unifiedRenderPath();
protected: protected:
explicit QuickItemNodeInstance(QQuickItem*); explicit QuickItemNodeInstance(QQuickItem*);
QQuickItem *quickItem() const; QQuickItem *quickItem() const;
@@ -118,6 +124,7 @@ protected:
double x() const; double x() const;
double y() const; double y() const;
bool checkIfRefFromEffect(qint32 id);
private: //variables private: //variables
QPointer<QQuickItem> m_contentItem; QPointer<QQuickItem> m_contentItem;
@@ -131,6 +138,7 @@ private: //variables
double m_width; double m_width;
double m_height; double m_height;
static bool s_createEffectItem; static bool s_createEffectItem;
static bool s_unifiedRenderPath;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -120,6 +120,11 @@ QImage ServerNodeInstance::renderPreviewImage(const QSize &previewImageSize) con
return m_nodeInstance->renderPreviewImage(previewImageSize); return m_nodeInstance->renderPreviewImage(previewImageSize);
} }
QSharedPointer<QQuickItemGrabResult> ServerNodeInstance::createGrabResult() const
{
return m_nodeInstance->createGrabResult();
}
bool ServerNodeInstance::isRootNodeInstance() const bool ServerNodeInstance::isRootNodeInstance() const
{ {
return isValid() && m_nodeInstance->isRootNodeInstance(); return isValid() && m_nodeInstance->isRootNodeInstance();

View File

@@ -40,6 +40,7 @@ class QGraphicsItem;
class QGraphicsTransform; class QGraphicsTransform;
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
class QQuickItem; class QQuickItem;
class QQuickItemGrabResult;
#endif #endif
QT_END_NAMESPACE QT_END_NAMESPACE
@@ -102,6 +103,8 @@ public:
QImage renderImage() const; QImage renderImage() const;
QImage renderPreviewImage(const QSize &previewImageSize) const; QImage renderPreviewImage(const QSize &previewImageSize) const;
QSharedPointer<QQuickItemGrabResult> createGrabResult() const;
ServerNodeInstance parent() const; ServerNodeInstance parent() const;
bool hasParent() const; bool hasParent() const;