diff options
13 files changed, 293 insertions, 207 deletions
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml index 002ed7bc04..1bdc73fb22 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml @@ -57,6 +57,8 @@ Item { property var selectionBoxes: [] property rect viewPortRect: Qt.rect(0, 0, 1000, 1000) + property bool shuttingDown: false + signal selectionChanged(var selectedNodes) signal commitObjectProperty(var object, var propName) signal changeObjectProperty(var object, var propName) @@ -71,6 +73,11 @@ Item { onActiveSceneChanged: updateActiveScene() + function aboutToShutDown() + { + shuttingDown = true; + } + function createEditView() { var component = Qt.createComponent("SceneView3D.qml"); @@ -125,8 +132,12 @@ Item { } else { // When active scene is deleted, this function gets called by object deletion // handlers without going through setActiveScene, so make sure sceneId is cleared. - sceneId = ""; - storeCurrentToolStates(); + // This is skipped during application shutdown, as calling QQuickText::setText() + // during application shutdown can crash the application. + if (!shuttingDown) { + sceneId = ""; + storeCurrentToolStates(); + } } notifyActiveSceneChange(); @@ -704,6 +715,10 @@ Item { Text { id: gizmoLabelText text: { + // This is skipped during application shutdown, as calling QQuickText::setText() + // during application shutdown can crash the application. + if (shuttingDown) + return text; var l = Qt.locale(); var targetProperty; if (viewRoot.selectedNode) { @@ -738,6 +753,10 @@ Item { Text { id: rotateGizmoLabelText text: { + // This is skipped during application shutdown, as calling QQuickText::setText() + // during application shutdown can crash the application. + if (shuttingDown) + return text; var l = Qt.locale(); if (rotateGizmo.targetNode) { var degrees = rotateGizmo.currentAngle * (180 / Math.PI); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp index 552d323247..64d790c6a7 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp @@ -189,9 +189,14 @@ NodeInstanceServer::NodeInstanceServer(NodeInstanceClientInterface *nodeInstance Internal::QmlPrivateGate::registerFixResourcePathsForObjectCallBack(); } +NodeInstanceServer::~NodeInstanceServer() +{ + m_objectInstanceHash.clear(); +} + QList<ServerNodeInstance> NodeInstanceServer::createInstances(const QVector<InstanceContainer> &containerVector) { - Q_ASSERT(declarativeView() || quickView()); + Q_ASSERT(declarativeView() || quickWindow()); QList<ServerNodeInstance> instanceList; for (const InstanceContainer &instanceContainer : containerVector) { ServerNodeInstance instance; @@ -207,7 +212,6 @@ QList<ServerNodeInstance> NodeInstanceServer::createInstances(const QVector<Inst m_rootNodeInstance = instance; if (quickView()) quickView()->setContent(fileUrl(), m_importComponent, m_rootNodeInstance.rootQuickItem()); - resizeCanvasSizeToRootItemSize(); } foreach (QQmlContext* context, allSubContextsForObject(instance.internalObject())) @@ -442,7 +446,7 @@ void NodeInstanceServer::removeSharedMemory(const RemoveSharedMemoryCommand &/*c void NodeInstanceServer::setupImports(const QVector<AddImportContainer> &containerVector) { - Q_ASSERT(quickView()); + Q_ASSERT(quickWindow()); QSet<QString> importStatementSet; QString qtQuickImport; @@ -497,8 +501,9 @@ void NodeInstanceServer::setupOnlyWorkingImports(const QStringList &workingImpor QByteArray componentCode = workingImportStatementList.join("\n").toUtf8().append("\n"); m_importCode = componentCode; - m_importComponent = new QQmlComponent(engine(), quickView()); - quickView()->setContent(fileUrl(), m_importComponent, quickView()->rootObject()); + m_importComponent = new QQmlComponent(engine(), quickWindow()); + if (quickView()) + quickView()->setContent(fileUrl(), m_importComponent, quickView()->rootObject()); m_importComponent->setData(componentCode.append("\nItem {}\n"), fileUrl()); m_importComponentObject = m_importComponent->create(); @@ -942,11 +947,9 @@ void NodeInstanceServer::setInstancePropertyVariant(const PropertyValueContainer if (hasInstanceForId(valueContainer.instanceId())) { ServerNodeInstance instance = instanceForId(valueContainer.instanceId()); - const PropertyName name = valueContainer.name(); const QVariant value = valueContainer.value(); - if (activeStateInstance().isValid() && !instance.isSubclassOf("QtQuick/PropertyChanges")) { bool stateValueWasUpdated = activeStateInstance().updateStateVariant(instance, name, value); if (!stateValueWasUpdated) { @@ -962,6 +965,9 @@ void NodeInstanceServer::setInstancePropertyVariant(const PropertyValueContainer if (valueContainer.isDynamic() && valueContainer.instanceId() == 0 && engine()) rootContext()->setContextProperty(QString::fromUtf8(name), Internal::QmlPrivateGate::fixResourcePaths(value)); + + if (valueContainer.instanceId() == 0 && (name == "width" || name == "height" || name == "x" || name == "y")) + resizeCanvasToRootItem(); } } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h index 021a2bd6d0..f44a0047fe 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h @@ -31,6 +31,7 @@ #include <QSet> #include <QStringList> #include <QPointer> +#include <QImage> #ifdef MULTILANGUAGE_TRANSLATIONPROVIDER #include <multilanguagelink.h> @@ -90,6 +91,7 @@ QT_BEGIN_NAMESPACE class QFileSystemWatcher; class QQmlView; class QQuickView; +class QQuickWindow; class QQmlEngine; class QFileInfo; class QQmlComponent; @@ -131,6 +133,7 @@ public: }; explicit NodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient); + ~NodeInstanceServer() override; void createInstances(const CreateInstancesCommand &command) override; void changeFileUrl(const ChangeFileUrlCommand &command) override; @@ -192,6 +195,9 @@ public: virtual QQmlView *declarativeView() const = 0; virtual QQuickView *quickView() const = 0; + virtual QQuickWindow *quickWindow() const = 0; + virtual QQuickItem *rootItem() const = 0; + virtual void setRootItem(QQuickItem *item) = 0; void sendDebugOutput(DebugOutputCommand::Type type, const QString &message, qint32 instanceId = 0); void sendDebugOutput(DebugOutputCommand::Type type, @@ -211,6 +217,8 @@ public: virtual void handleInstanceLocked(const ServerNodeInstance &instance, bool enable, bool checkAncestors); virtual void handleInstanceHidden(const ServerNodeInstance &instance, bool enable, bool checkAncestors); + virtual QImage grabWindow() = 0; + public slots: void refreshLocalFileProperty(const QString &path); void refreshDummyData(const QString &path); @@ -288,7 +296,7 @@ protected: QList<QQmlContext*> allSubContextsForObject(QObject *object); static QList<QObject*> allSubObjectsForObject(QObject *object); - virtual void resizeCanvasSizeToRootItemSize() = 0; + virtual void resizeCanvasToRootItem() = 0; void setupState(qint32 stateInstanceId); private: diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5captureimagenodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5captureimagenodeinstanceserver.cpp index d24c4e5552..4581bc6ce8 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5captureimagenodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5captureimagenodeinstanceserver.cpp @@ -70,7 +70,7 @@ void Qt5CaptureImageNodeInstanceServer::collectItemChangesAndSendChangeCommands( auto rooNodeInstance = rootNodeInstance(); rooNodeInstance.rootQuickItem()->setClip(true); - DesignerSupport::polishItems(quickView()); + DesignerSupport::polishItems(quickWindow()); QImage image = renderImage(rooNodeInstance); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5capturepreviewnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5capturepreviewnodeinstanceserver.cpp index 7fb87defb0..b9ba3860a3 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5capturepreviewnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5capturepreviewnodeinstanceserver.cpp @@ -88,7 +88,7 @@ void Qt5CapturePreviewNodeInstanceServer::collectItemChangesAndSendChangeCommand if (!inFunction) { inFunction = true; - DesignerSupport::polishItems(quickView()); + DesignerSupport::polishItems(quickWindow()); QVector<CapturedDataCommand::StateData> stateDatas; stateDatas.push_back(collectStateData(rootNodeInstance(), nodeInstances(), 0)); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index 8421064021..521ef40765 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -88,11 +88,7 @@ #include <QtGui/qguiapplication.h> #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) -#include <QtGui/private/qrhi_p.h> -#include <QtQuick/private/qquickwindow_p.h> -#include <QtQuick/private/qsgrenderer_p.h> #include <QtQuick/private/qquickrendercontrol_p.h> -#include <QtQuick/private/qquickrendertarget_p.h> #endif #ifdef QUICK3D_MODULE @@ -149,7 +145,7 @@ void Qt5InformationNodeInstanceServer::createAuxiliaryQuickView(const QUrl &url, #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) viewData.window = new QQuickView(quickView()->engine(), quickView()); viewData.window->setFormat(quickView()->format()); - DesignerSupport::createOpenGLContext(static_cast<QQuickView *>(viewData.window)); + DesignerSupport::createOpenGLContext(static_cast<QQuickView *>(viewData.window.data())); #else viewData.renderControl = new QQuickRenderControl; viewData.window = new QQuickWindow(viewData.renderControl); @@ -165,7 +161,7 @@ void Qt5InformationNodeInstanceServer::createAuxiliaryQuickView(const QUrl &url, } #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - DesignerSupport::setRootItem(static_cast<QQuickView *>(viewData.window), viewData.rootItem); + DesignerSupport::setRootItem(static_cast<QQuickView *>(viewData.window.data()), viewData.rootItem); #else viewData.window->contentItem()->setSize(viewData.rootItem->size()); viewData.window->setGeometry(0, 0, viewData.rootItem->width(), viewData.rootItem->height()); @@ -249,120 +245,6 @@ void Qt5InformationNodeInstanceServer::handleInputEvents() } } -bool Qt5InformationNodeInstanceServer::initRhi(RenderViewData &viewData) -{ -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - if (!viewData.renderControl) { - qWarning() << __FUNCTION__ << "Render control not created"; - return false; - } - - if (!viewData.rhi) { - QQuickRenderControlPrivate *rd = QQuickRenderControlPrivate::get(viewData.renderControl); - viewData.rhi = rd->rhi; - - if (!viewData.rhi) { - qWarning() << __FUNCTION__ << "Rhi is null"; - return false; - } - } - - auto cleanRhiResources = [&viewData]() { - // Releasing cached resources is a workaround for bug QTBUG-88761 - auto renderer = QQuickWindowPrivate::get(viewData.window)->renderer; - if (renderer) - renderer->releaseCachedResources(); - - if (viewData.rpDesc) { - viewData.rpDesc->deleteLater(); - viewData.rpDesc = nullptr; - } - if (viewData.texTarget) { - viewData.texTarget->deleteLater(); - viewData.texTarget = nullptr; - } - if (viewData.buffer) { - viewData.buffer->deleteLater(); - viewData.buffer = nullptr; - } - if (viewData.texture) { - viewData.texture->deleteLater(); - viewData.texture = nullptr; - } - }; - if (viewData.bufferDirty) { - cleanRhiResources(); - viewData.bufferDirty = false; - } - - const QSize size = viewData.rootItem->size().toSize(); - viewData.texture = viewData.rhi->newTexture(QRhiTexture::RGBA8, size, 1, - QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource); - if (!viewData.texture->create()) { - qWarning() << __FUNCTION__ << "QRhiTexture creation failed"; - cleanRhiResources(); - return false; - } - - viewData.buffer = viewData.rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, size, 1); - if (!viewData.buffer->create()) { - qWarning() << __FUNCTION__ << "Depth/stencil buffer creation failed"; - cleanRhiResources(); - return false; - } - - QRhiTextureRenderTargetDescription rtDesc(QRhiColorAttachment(viewData.texture)); - rtDesc.setDepthStencilBuffer(viewData.buffer); - viewData.texTarget = viewData.rhi->newTextureRenderTarget(rtDesc); - viewData.rpDesc = viewData.texTarget->newCompatibleRenderPassDescriptor(); - viewData.texTarget->setRenderPassDescriptor(viewData.rpDesc); - if (!viewData.texTarget->create()) { - qWarning() << __FUNCTION__ << "Texture render target creation failed"; - cleanRhiResources(); - return false; - } - - // redirect Qt Quick rendering into our texture - viewData.window->setRenderTarget(QQuickRenderTarget::fromRhiRenderTarget(viewData.texTarget)); -#endif - return true; -} - -QImage Qt5InformationNodeInstanceServer::grabRenderControl(RenderViewData &viewData) -{ - QImage renderImage; -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - if (viewData.bufferDirty && !initRhi(viewData)) - return renderImage; - - viewData.renderControl->polishItems(); - viewData.renderControl->beginFrame(); - viewData.renderControl->sync(); - viewData.renderControl->render(); - - bool readCompleted = false; - QRhiReadbackResult readResult; - readResult.completed = [&] { - readCompleted = true; - QImage wrapperImage(reinterpret_cast<const uchar *>(readResult.data.constData()), - readResult.pixelSize.width(), readResult.pixelSize.height(), - QImage::Format_RGBA8888_Premultiplied); - if (viewData.rhi->isYUpInFramebuffer()) - renderImage = wrapperImage.mirrored(); - else - renderImage = wrapperImage.copy(); - }; - QRhiResourceUpdateBatch *readbackBatch = viewData.rhi->nextResourceUpdateBatch(); - readbackBatch->readBackTexture(viewData.texture, &readResult); - - QQuickRenderControlPrivate *rd = QQuickRenderControlPrivate::get(viewData.renderControl); - rd->cb->resourceUpdate(readbackBatch); - - viewData.renderControl->endFrame(); -#endif - return renderImage; -} - void Qt5InformationNodeInstanceServer::createEditView3D() { #ifdef QUICK3D_MODULE @@ -1000,17 +882,13 @@ Qt5InformationNodeInstanceServer::~Qt5InformationNodeInstanceServer() m_render3DEditViewTimer.stop(); m_inputEventTimer.stop(); - delete m_editView3DData.rootItem; - delete m_editView3DData.window; - delete m_modelNode3DImageViewData.rootItem; - delete m_modelNode3DImageViewData.window; - delete m_modelNode2DImageViewData.rootItem; - delete m_modelNode2DImageViewData.window; - for (auto view : qAsConst(m_view3Ds)) view->disconnect(); - for (auto scene : qAsConst(m_3DSceneMap)) - scene->disconnect(); + for (auto node : qAsConst(m_3DSceneMap)) + node->disconnect(); + + if (m_editView3DData.rootItem) + QMetaObject::invokeMethod(m_editView3DData.rootItem, "aboutToShutDown", Qt::DirectConnection); } void Qt5InformationNodeInstanceServer::sendTokenBack() @@ -1424,12 +1302,12 @@ void Qt5InformationNodeInstanceServer::collectItemChangesAndSendChangeCommands() if (!inFunction) { inFunction = true; - DesignerSupport::polishItems(quickView()); + DesignerSupport::polishItems(quickWindow()); QSet<ServerNodeInstance> informationChangedInstanceSet; QVector<InstancePropertyPair> propertyChangedList; - if (quickView()) { + if (quickWindow()) { foreach (QQuickItem *item, allItems()) { if (item && hasInstanceForObject(item)) { ServerNodeInstance instance = instanceForObject(item); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h index 47dacd45db..353f57b3fc 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h @@ -39,15 +39,6 @@ QT_BEGIN_NAMESPACE class QDragMoveEvent; -class QQuickWindow; -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) -class QQuickRenderControl; -class QRhi; -class QRhiTexture; -class QRhiRenderBuffer; -class QRhiTextureRenderTarget; -class QRhiRenderPassDescriptor; -#endif QT_END_NAMESPACE namespace QmlDesigner { @@ -141,23 +132,6 @@ private: void updateLockedAndHiddenStates(const QSet<ServerNodeInstance> &instances); void handleInputEvents(); - struct RenderViewData { - QQuickWindow *window = nullptr; - QQuickItem *rootItem = nullptr; - QQuickItem *contentItem = nullptr; -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - bool bufferDirty = true; - QQuickRenderControl *renderControl = nullptr; - QRhi *rhi = nullptr; - QRhiTexture *texture = nullptr; - QRhiRenderBuffer *buffer = nullptr; - QRhiTextureRenderTarget *texTarget = nullptr; - QRhiRenderPassDescriptor *rpDesc = nullptr; -#endif - }; - - bool initRhi(RenderViewData &viewData); - QImage grabRenderControl(RenderViewData &viewData); void createAuxiliaryQuickView(const QUrl &url, RenderViewData &viewData); RenderViewData m_editView3DData; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp index 90f959dd2b..620ed0352b 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp @@ -31,6 +31,7 @@ #include <QQuickItem> #include <QQuickView> +#include <QQuickWindow> #include <designersupportdelegate.h> #include <addimportcontainer.h> @@ -40,6 +41,14 @@ #include <QDebug> #include <QOpenGLContext> +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +#include <QtGui/private/qrhi_p.h> +#include <QtQuick/private/qquickwindow_p.h> +#include <QtQuick/private/qsgrenderer_p.h> +#include <QtQuick/private/qquickrendercontrol_p.h> +#include <QtQuick/private/qquickrendertarget_p.h> +#endif + namespace QmlDesigner { Qt5NodeInstanceServer::Qt5NodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) @@ -50,30 +59,44 @@ Qt5NodeInstanceServer::Qt5NodeInstanceServer(NodeInstanceClientInterface *nodeIn Qt5NodeInstanceServer::~Qt5NodeInstanceServer() { - delete quickView(); + delete quickWindow(); } QQuickView *Qt5NodeInstanceServer::quickView() const { - return m_quickView.data(); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + return static_cast<QQuickView *>(m_viewData.window.data()); +#else + return nullptr; +#endif } -void Qt5NodeInstanceServer::initializeView() +QQuickWindow *Qt5NodeInstanceServer::quickWindow() const { - Q_ASSERT(!quickView()); + return m_viewData.window.data(); +} - m_quickView = new QQuickView; +void Qt5NodeInstanceServer::initializeView() +{ + Q_ASSERT(!quickWindow()); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + auto view = new QQuickView; + m_viewData.window = view; /* enables grab window without show */ - QSurfaceFormat surfaceFormat = m_quickView->requestedFormat(); + QSurfaceFormat surfaceFormat = view->requestedFormat(); surfaceFormat.setVersion(4, 1); surfaceFormat.setProfile(QSurfaceFormat::CoreProfile); QSurfaceFormat::setDefaultFormat(surfaceFormat); - - m_quickView->setFormat(surfaceFormat); - - DesignerSupport::createOpenGLContext(m_quickView.data()); + view->setFormat(surfaceFormat); + + DesignerSupport::createOpenGLContext(view); + m_qmlEngine = view->engine(); +#else + m_viewData.renderControl = new QQuickRenderControl; + m_viewData.window = new QQuickWindow(m_viewData.renderControl); + m_viewData.renderControl->initialize(); + m_qmlEngine = new QQmlEngine; #endif if (qEnvironmentVariableIsSet("QML_FILE_SELECTORS")) { @@ -90,16 +113,39 @@ QQmlView *Qt5NodeInstanceServer::declarativeView() const return nullptr; } -QQmlEngine *Qt5NodeInstanceServer::engine() const +QQuickItem *Qt5NodeInstanceServer::rootItem() const { - if (quickView()) - return quickView()->engine(); + return m_viewData.rootItem; +} - return nullptr; +void Qt5NodeInstanceServer::setRootItem(QQuickItem *item) +{ + m_viewData.rootItem = item; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + DesignerSupport::setRootItem(quickView(), item); +#else + quickWindow()->setGeometry(0, 0, item->width(), item->height()); + // Insert an extra item above the root to adjust root item position to 0,0 to make entire + // item to be always rendered. + if (!m_viewData.contentItem) + m_viewData.contentItem = new QQuickItem(quickWindow()->contentItem()); + m_viewData.contentItem->setPosition(-item->position()); + item->setParentItem(m_viewData.contentItem); +#endif } -void Qt5NodeInstanceServer::resizeCanvasSizeToRootItemSize() +QQmlEngine *Qt5NodeInstanceServer::engine() const { + return m_qmlEngine; +} + +void Qt5NodeInstanceServer::resizeCanvasToRootItem() +{ +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + m_viewData.bufferDirty = true; + m_viewData.contentItem->setPosition(-m_viewData.rootItem->position()); +#endif + quickWindow()->resize(rootNodeInstance().boundingRect().size().toSize()); } void Qt5NodeInstanceServer::resetAllItems() @@ -116,7 +162,7 @@ void Qt5NodeInstanceServer::setupScene(const CreateSceneCommand &command) setupDummyData(command.fileUrl); setupInstances(command); - quickView()->resize(rootNodeInstance().boundingRect().size().toSize()); + resizeCanvasToRootItem(); } QList<QQuickItem*> subItems(QQuickItem *parentItem) @@ -138,6 +184,127 @@ QList<QQuickItem*> Qt5NodeInstanceServer::allItems() const return QList<QQuickItem*>(); } +bool Qt5NodeInstanceServer::initRhi(RenderViewData &viewData) +{ +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + if (!viewData.renderControl) { + qWarning() << __FUNCTION__ << "Render control not created"; + return false; + } + + if (!viewData.rhi) { + QQuickRenderControlPrivate *rd = QQuickRenderControlPrivate::get(viewData.renderControl); + viewData.rhi = rd->rhi; + + if (!viewData.rhi) { + qWarning() << __FUNCTION__ << "Rhi is null"; + return false; + } + } + + auto cleanRhiResources = [&viewData]() { + // Releasing cached resources is a workaround for bug QTBUG-88761 + auto renderer = QQuickWindowPrivate::get(viewData.window)->renderer; + if (renderer) + renderer->releaseCachedResources(); + + if (viewData.rpDesc) { + viewData.rpDesc->deleteLater(); + viewData.rpDesc = nullptr; + } + if (viewData.texTarget) { + viewData.texTarget->deleteLater(); + viewData.texTarget = nullptr; + } + if (viewData.buffer) { + viewData.buffer->deleteLater(); + viewData.buffer = nullptr; + } + if (viewData.texture) { + viewData.texture->deleteLater(); + viewData.texture = nullptr; + } + }; + if (viewData.bufferDirty) { + cleanRhiResources(); + viewData.bufferDirty = false; + } + + const QSize size = viewData.window->size(); + viewData.texture = viewData.rhi->newTexture(QRhiTexture::RGBA8, size, 1, + QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource); + if (!viewData.texture->create()) { + qWarning() << __FUNCTION__ << "QRhiTexture creation failed"; + cleanRhiResources(); + return false; + } + + viewData.buffer = viewData.rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, size, 1); + if (!viewData.buffer->create()) { + qWarning() << __FUNCTION__ << "Depth/stencil buffer creation failed"; + cleanRhiResources(); + return false; + } + + QRhiTextureRenderTargetDescription rtDesc(QRhiColorAttachment(viewData.texture)); + rtDesc.setDepthStencilBuffer(viewData.buffer); + viewData.texTarget = viewData.rhi->newTextureRenderTarget(rtDesc); + viewData.rpDesc = viewData.texTarget->newCompatibleRenderPassDescriptor(); + viewData.texTarget->setRenderPassDescriptor(viewData.rpDesc); + if (!viewData.texTarget->create()) { + qWarning() << __FUNCTION__ << "Texture render target creation failed"; + cleanRhiResources(); + return false; + } + + // redirect Qt Quick rendering into our texture + viewData.window->setRenderTarget(QQuickRenderTarget::fromRhiRenderTarget(viewData.texTarget)); +#endif + return true; +} + +QImage Qt5NodeInstanceServer::grabRenderControl(RenderViewData &viewData) +{ + QImage renderImage; +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + if (viewData.bufferDirty && !initRhi(viewData)) + return renderImage; + + viewData.renderControl->polishItems(); + viewData.renderControl->beginFrame(); + viewData.renderControl->sync(); + viewData.renderControl->render(); + + bool readCompleted = false; + QRhiReadbackResult readResult; + readResult.completed = [&] { + readCompleted = true; + QImage wrapperImage(reinterpret_cast<const uchar *>(readResult.data.constData()), + readResult.pixelSize.width(), readResult.pixelSize.height(), + QImage::Format_RGBA8888_Premultiplied); + if (viewData.rhi->isYUpInFramebuffer()) + renderImage = wrapperImage.mirrored(); + else + renderImage = wrapperImage.copy(); + }; + QRhiResourceUpdateBatch *readbackBatch = viewData.rhi->nextResourceUpdateBatch(); + readbackBatch->readBackTexture(viewData.texture, &readResult); + + QQuickRenderControlPrivate *rd = QQuickRenderControlPrivate::get(viewData.renderControl); + rd->cb->resourceUpdate(readbackBatch); + + viewData.renderControl->endFrame(); +#endif + return renderImage; +} + +QImage Qt5NodeInstanceServer::grabWindow() +{ + if (m_viewData.rootItem) + return grabRenderControl(m_viewData); + return {}; +} + void Qt5NodeInstanceServer::refreshBindings() { DesignerSupport::refreshExpressions(context()); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.h index ca43363a9a..e6a2754f99 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.h @@ -26,12 +26,22 @@ #pragma once #include <QtGlobal> +#include <QtQuick/qquickwindow.h> #include "nodeinstanceserver.h" #include <designersupportdelegate.h> QT_BEGIN_NAMESPACE class QQuickItem; +class QQmlEngine; +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +class QQuickRenderControl; +class QRhi; +class QRhiTexture; +class QRhiRenderBuffer; +class QRhiTextureRenderTarget; +class QRhiRenderPassDescriptor; +#endif QT_END_NAMESPACE namespace QmlDesigner { @@ -44,7 +54,11 @@ public: ~Qt5NodeInstanceServer() override; QQuickView *quickView() const override; + QQuickWindow *quickWindow() const override; QQmlView *declarativeView() const override; + QQuickItem *rootItem() const override; + void setRootItem(QQuickItem *item) override; + QQmlEngine *engine() const override; void refreshBindings() override; @@ -54,16 +68,37 @@ public: void clearScene(const ClearSceneCommand &command) override; void reparentInstances(const ReparentInstancesCommand &command) override; + QImage grabWindow() override; + protected: void initializeView() override; - void resizeCanvasSizeToRootItemSize() override; + void resizeCanvasToRootItem() override; void resetAllItems(); void setupScene(const CreateSceneCommand &command) override; QList<QQuickItem*> allItems() const; + struct RenderViewData { + QPointer<QQuickWindow> window = nullptr; + QQuickItem *rootItem = nullptr; + QQuickItem *contentItem = nullptr; +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + bool bufferDirty = true; + QQuickRenderControl *renderControl = nullptr; + QRhi *rhi = nullptr; + QRhiTexture *texture = nullptr; + QRhiRenderBuffer *buffer = nullptr; + QRhiTextureRenderTarget *texTarget = nullptr; + QRhiRenderPassDescriptor *rpDesc = nullptr; +#endif + }; + + virtual bool initRhi(RenderViewData &viewData); + virtual QImage grabRenderControl(RenderViewData &viewData); + private: - QPointer<QQuickView> m_quickView; + RenderViewData m_viewData; DesignerSupport m_designerSupport; + QQmlEngine *m_qmlEngine = nullptr; }; } // QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.cpp index ae167ad6ca..2a34864a84 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.cpp @@ -71,7 +71,7 @@ void Qt5PreviewNodeInstanceServer::collectItemChangesAndSendChangeCommands() if (!inFunction && nodeInstanceClient()->bytesToWrite() < 10000) { inFunction = true; - DesignerSupport::polishItems(quickView()); + DesignerSupport::polishItems(quickWindow()); QVector<ImageContainer> imageContainerVector; imageContainerVector.append(ImageContainer(0, renderPreviewImage(), -1)); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp index 4a45c626be..bb1aa72445 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp @@ -74,9 +74,9 @@ void Qt5RenderNodeInstanceServer::collectItemChangesAndSendChangeCommands() if (!inFunction) { inFunction = true; - DesignerSupport::polishItems(quickView()); + DesignerSupport::polishItems(quickWindow()); - if (quickView() && nodeInstanceClient()->bytesToWrite() < 10000) { + if (quickWindow() && nodeInstanceClient()->bytesToWrite() < 10000) { foreach (QQuickItem *item, allItems()) { if (item) { if (hasInstanceForObject(item)) { diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5testnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5testnodeinstanceserver.cpp index a6570b4a1e..9edb567d5b 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5testnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5testnodeinstanceserver.cpp @@ -257,13 +257,13 @@ void Qt5TestNodeInstanceServer::removeSharedMemory(const RemoveSharedMemoryComma void QmlDesigner::Qt5TestNodeInstanceServer::collectItemChangesAndSendChangeCommands() { - DesignerSupport::polishItems(quickView()); + DesignerSupport::polishItems(quickWindow()); QSet<ServerNodeInstance> informationChangedInstanceSet; QVector<InstancePropertyPair> propertyChangedList; QSet<ServerNodeInstance> parentChangedSet; - if (quickView()) { + if (quickWindow()) { foreach (QQuickItem *item, allItems()) { if (item && hasInstanceForObject(item)) { ServerNodeInstance instance = instanceForObject(item); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp index e9e6328ce9..81607cbdd6 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp @@ -174,11 +174,10 @@ void QuickItemNodeInstance::initialize(const ObjectNodeInstance::Pointer &object InstanceContainer::NodeFlags flags) { - if (instanceId() == 0) { - DesignerSupport::setRootItem(nodeInstanceServer()->quickView(), quickItem()); - } else { - quickItem()->setParentItem(qobject_cast<QQuickItem*>(nodeInstanceServer()->quickView()->rootObject())); - } + if (instanceId() == 0) + nodeInstanceServer()->setRootItem(quickItem()); + else + quickItem()->setParentItem(nodeInstanceServer()->rootItem()); if (quickItem()->window() && checkIfRefFromEffect(instanceId())) { designerSupport()->refFromEffectItem(quickItem(), @@ -420,19 +419,19 @@ QImage QuickItemNodeInstance::renderImage() const #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) if (s_unifiedRenderPath) { - renderImage = nodeInstanceServer()->quickView()->grabWindow(); + renderImage = nodeInstanceServer()->quickWindow()->grabWindow(); } else { // Fake render loop signaling to update things like QML items as 3D textures - nodeInstanceServer()->quickView()->beforeSynchronizing(); - nodeInstanceServer()->quickView()->beforeRendering(); + nodeInstanceServer()->quickWindow()->beforeSynchronizing(); + nodeInstanceServer()->quickWindow()->beforeRendering(); renderImage = designerSupport()->renderImageForItem(quickItem(), renderBoundingRect, size); - nodeInstanceServer()->quickView()->afterRendering(); + nodeInstanceServer()->quickWindow()->afterRendering(); } renderImage.setDevicePixelRatio(devicePixelRatio); #else - renderImage = nodeInstanceServer()->quickView()->grabWindow(); + renderImage = nodeInstanceServer()->grabWindow(); renderImage = renderImage.copy(renderBoundingRect.toRect()); /* When grabbing an offscren window the device pixel ratio is 1 */ renderImage.setDevicePixelRatio(1); @@ -452,20 +451,20 @@ QImage QuickItemNodeInstance::renderPreviewImage(const QSize &previewImageSize) QImage image; #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) if (s_unifiedRenderPath) { - image = nodeInstanceServer()->quickView()->grabWindow(); + image = nodeInstanceServer()->quickWindow()->grabWindow(); } else { // Fake render loop signaling to update things like QML items as 3D textures - nodeInstanceServer()->quickView()->beforeSynchronizing(); - nodeInstanceServer()->quickView()->beforeRendering(); + nodeInstanceServer()->quickWindow()->beforeSynchronizing(); + nodeInstanceServer()->quickWindow()->beforeRendering(); image = designerSupport()->renderImageForItem(quickItem(), previewItemBoundingRect, size); - nodeInstanceServer()->quickView()->afterRendering(); + nodeInstanceServer()->quickWindow()->afterRendering(); } #else - image = nodeInstanceServer()->quickView()->grabWindow(); + image = nodeInstanceServer()->grabWindow(); image = image.copy(previewItemBoundingRect.toRect()); #endif |