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 <changelanguagecommand.h>
#include <designersupportdelegate.h>
#include <QAbstractAnimation>
#include <QDebug>
#include <QQmlEngine>
#include <QQmlApplicationEngine>
#include <QFileSystemWatcher>
#include <QUrl>
#include <QSet>
#include <QDir>
#include <QVariant>
#include <QFileSystemWatcher>
#include <QMetaType>
#include <QMutableVectorIterator>
#include <QQmlApplicationEngine>
#include <QQmlComponent>
#include <QQmlContext>
#include <qqmllist.h>
#include <QAbstractAnimation>
#include <QQmlEngine>
#include <QQuickItemGrabResult>
#include <QQuickView>
#include <QSet>
#include <designersupportdelegate.h>
#include <QUrl>
#include <QVariant>
#include <qqmllist.h>
#include <algorithm>
@@ -1461,4 +1462,19 @@ void NodeInstanceServer::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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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());

View File

@@ -87,16 +87,26 @@ void Qt5RenderNodeInstanceServer::collectItemChangesAndSendChangeCommands()
if (ancestorInstance.isValid())
m_dirtyInstanceSet.insert(ancestorInstance);
}
DesignerSupport::updateDirtyNode(item);
Internal::QuickItemNodeInstance::updateDirtyNode(item);
}
}
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()) {
nodeInstanceClient()->pixmapChanged(createPixmapChangedCommand(QtHelpers::toList(m_dirtyInstanceSet)));
nodeInstanceClient()->pixmapChanged(
createPixmapChangedCommand(QtHelpers::toList(m_dirtyInstanceSet)));
m_dirtyInstanceSet.clear();
}
}
m_dirtyInstanceSet.clear();
resetAllItems();
@@ -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)

View File

@@ -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<QQuickItem*>(nodeInstanceServer()->quickView()->rootObject()));
}
if (quickItem()->window()) {
if (s_createEffectItem || instanceId() == 0)
if (quickItem()->window() && checkIfRefFromEffect(instanceId())) {
designerSupport()->refFromEffectItem(quickItem(),
!flags.testFlag(InstanceContainer::ParentTakesOverRendering));
!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<QQuickItemGrabResult> 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())
const QList<QQuickItem *> children = parentItem->childItems();
for (QQuickItem *childItem : children)
updateAllDirtyNodesRecursive(childItem);
DesignerSupport::updateDirtyNode(parentItem);
updateDirtyNode(parentItem);
}
static inline bool isRectangleSane(const QRectF &rect)

View File

@@ -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<QQuickItemGrabResult> createGrabResult() const override;
void updateAllDirtyNodesRecursive() override;
@@ -98,6 +101,9 @@ public:
QList<QQuickItem*> 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<QQuickItem> m_contentItem;
@@ -131,6 +138,7 @@ private: //variables
double m_width;
double m_height;
static bool s_createEffectItem;
static bool s_unifiedRenderPath;
};
} // namespace Internal

View File

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

View File

@@ -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<QQuickItemGrabResult> createGrabResult() const;
ServerNodeInstance parent() const;
bool hasParent() const;