aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@qt.io>2020-11-17 17:56:45 +0200
committerMiikka Heikkinen <miikka.heikkinen@qt.io>2020-11-27 12:11:28 +0000
commitae15780f8477325659f34cd70d2d1017615593ce (patch)
tree805c6bf622ac7a28cd2d4c025c715577b8db451c
parenta0dd5d2b4fdbf6704240265cc4717e2f8ef9c24e (diff)
QmlPuppet: Hide 3D edit view render window
Rendering is now done using QRhi private API and QQuickRenderControl. In addition, input event handling was changed to use sendEvent instead of postEvent for our fake mouse events, as mouse event position gets corrupted somehow if event is handled asynchronously when the window is hidden. Change-Id: Ia2466622cd4b60e3f73e0ad3e7e4da7c7c335451 Fixes: QDS-3125 Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/ModelNode3DImageView.qml5
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.cpp176
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.h27
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp440
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h45
5 files changed, 492 insertions, 201 deletions
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/ModelNode3DImageView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/ModelNode3DImageView.qml
index ac5fff1e3e..324a020d6f 100644
--- a/share/qtcreator/qml/qmlpuppet/mockfiles/ModelNode3DImageView.qml
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/ModelNode3DImageView.qml
@@ -50,11 +50,8 @@ Item {
view.destroy();
}
- function createViewForObject(obj, w, h)
+ function createViewForObject(obj)
{
- width = w;
- height = h;
-
if (obj instanceof Material)
createViewForMaterial(obj);
else if (obj instanceof Model)
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.cpp
index a54373f983..d3dc35f221 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.cpp
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.cpp
@@ -45,6 +45,12 @@
#include <QtQuick3D/private/qquick3dviewport_p.h>
#endif
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+#include <QtGui/private/qrhi_p.h>
+#include <QtQuick/private/qquickrendercontrol_p.h>
+#include <QtQuick/private/qquickrendertarget_p.h>
+#endif
+
#include <private/qquickdesignersupportitems_p.h>
IconRenderer::IconRenderer(int size, const QString &filePath, const QString &source)
@@ -62,23 +68,26 @@ void IconRenderer::setupRender()
DesignerSupport::activateDesignerWindowManager();
#endif
- m_quickView = new QQuickView;
-
+ QQmlEngine *engine = nullptr;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- QSurfaceFormat surfaceFormat = m_quickView->requestedFormat();
+ auto view = new QQuickView;
+ engine = view->engine();
+ m_window = view;
+ QSurfaceFormat surfaceFormat = view->requestedFormat();
surfaceFormat.setVersion(4, 1);
surfaceFormat.setProfile(QSurfaceFormat::CoreProfile);
- m_quickView->setFormat(surfaceFormat);
-
- DesignerSupport::createOpenGLContext(m_quickView);
+ view->setFormat(surfaceFormat);
+ DesignerSupport::createOpenGLContext(view);
#else
- m_quickView->setDefaultAlphaBuffer(true);
- m_quickView->setColor(Qt::transparent);
- m_ratio = m_quickView->devicePixelRatio();
- m_quickView->installEventFilter(this);
+ engine = new QQmlEngine;
+ m_renderControl = new QQuickRenderControl;
+ m_window = new QQuickWindow(m_renderControl);
+ m_window->setDefaultAlphaBuffer(true);
+ m_window->setColor(Qt::transparent);
+ m_renderControl->initialize();
#endif
- QQmlComponent component(m_quickView->engine());
+ QQmlComponent component(engine);
component.loadUrl(QUrl::fromLocalFile(m_source));
QObject *iconItem = component.create();
@@ -86,13 +95,19 @@ void IconRenderer::setupRender()
#ifdef QUICK3D_MODULE
if (auto scene = qobject_cast<QQuick3DNode *>(iconItem)) {
qmlRegisterType<QmlDesigner::Internal::SelectionBoxGeometry>("SelectionBoxGeometry", 1, 0, "SelectionBoxGeometry");
- QQmlComponent component(m_quickView->engine());
+ QQmlComponent component(engine);
component.loadUrl(QUrl("qrc:/qtquickplugin/mockfiles/IconRenderer3D.qml"));
m_containerItem = qobject_cast<QQuickItem *>(component.create());
- DesignerSupport::setRootItem(m_quickView, m_containerItem);
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+ DesignerSupport::setRootItem(view, m_containerItem);
+#else
+ m_window->contentItem()->setSize(m_containerItem->size());
+ m_window->setGeometry(0, 0, m_containerItem->width(), m_containerItem->height());
+ m_containerItem->setParentItem(m_window->contentItem());
+#endif
auto helper = new QmlDesigner::Internal::GeneralHelper();
- m_quickView->engine()->rootContext()->setContextProperty("_generalHelper", helper);
+ engine->rootContext()->setContextProperty("_generalHelper", helper);
m_contentItem = QQmlProperty::read(m_containerItem, "view3D").value<QQuickItem *>();
auto view3D = qobject_cast<QQuick3DViewport *>(m_contentItem);
@@ -104,21 +119,21 @@ void IconRenderer::setupRender()
m_contentItem = scene;
m_containerItem = new QQuickItem();
m_containerItem->setSize(QSizeF(1024, 1024));
- DesignerSupport::setRootItem(m_quickView, m_containerItem);
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+ DesignerSupport::setRootItem(view, m_containerItem);
+#else
+ m_window->contentItem()->setSize(m_containerItem->size());
+ m_window->setGeometry(0, 0, m_containerItem->width(), m_containerItem->height());
+ m_containerItem->setParentItem(m_window->contentItem());
+#endif
m_contentItem->setParentItem(m_containerItem);
}
if (m_containerItem && m_contentItem) {
resizeContent(m_size);
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+ if (!initRhi())
+ QTimer::singleShot(0, qGuiApp, &QGuiApplication::quit);
QTimer::singleShot(0, this, &IconRenderer::createIcon);
-#else
- m_quickView->show();
- m_quickView->lower();
-
- // Failsafe to exit eventually if window fails to expose
- QTimer::singleShot(10000, qGuiApp, &QGuiApplication::quit);
-#endif
} else {
QTimer::singleShot(0, qGuiApp, &QGuiApplication::quit);
}
@@ -127,25 +142,12 @@ void IconRenderer::setupRender()
}
}
-bool IconRenderer::eventFilter(QObject *watched, QEvent *event)
-{
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
- if (watched == m_quickView && event->type() == QEvent::Expose)
- QTimer::singleShot(0, this, &IconRenderer::createIcon);
-#else
- Q_UNUSED(watched)
- Q_UNUSED(event)
-#endif
- return false;
-}
-
void IconRenderer::createIcon()
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- m_designerSupport.refFromEffectItem(m_quickView->rootObject(), false);
+ m_designerSupport.refFromEffectItem(m_containerItem, false);
#endif
- QQuickDesignerSupportItems::disableNativeTextRendering(m_quickView->rootObject());
-
+ QQuickDesignerSupportItems::disableNativeTextRendering(m_containerItem);
#ifdef QUICK3D_MODULE
if (m_is3D) {
// Render once to make sure scene is up to date before we set up the selection box
@@ -166,6 +168,8 @@ void IconRenderer::createIcon()
// Render @2x image
resizeContent(m_size * 2);
+ if (!initRhi())
+ QTimer::singleShot(1000, qGuiApp, &QGuiApplication::quit);
QString saveFile;
saveFile = fi.absolutePath() + '/' + fi.completeBaseName() + "@2x";
@@ -194,23 +198,39 @@ void IconRenderer::render(const QString &fileName)
item->update();
#endif
};
- updateNodesRecursive(m_quickView->rootObject());
+ updateNodesRecursive(m_containerItem);
QRect rect(QPoint(), m_contentItem->size().toSize());
+ QImage renderImage;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- QImage renderImage = m_designerSupport.renderImageForItem(m_quickView->rootObject(),
- rect, rect.size());
+ renderImage = m_designerSupport.renderImageForItem(m_containerItem, rect, rect.size());
#else
- QImage renderImage = m_quickView->grabWindow();
+ m_renderControl->polishItems();
+ m_renderControl->beginFrame();
+ m_renderControl->sync();
+ m_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 (m_rhi->isYUpInFramebuffer())
+ renderImage = wrapperImage.mirrored().copy(0, 0, rect.width(), rect.height());
+ else
+ renderImage = wrapperImage.copy(0, 0, rect.width(), rect.height());
+ };
+ QRhiResourceUpdateBatch *readbackBatch = m_rhi->nextResourceUpdateBatch();
+ readbackBatch->readBackTexture(m_texture, &readResult);
+
+ QQuickRenderControlPrivate *rd = QQuickRenderControlPrivate::get(m_renderControl);
+ rd->cb->resourceUpdate(readbackBatch);
+
+ m_renderControl->endFrame();
#endif
if (!fileName.isEmpty()) {
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
- if (m_ratio != 1.) {
- rect.setWidth(qRound(rect.size().width() * m_ratio));
- rect.setHeight(qRound(rect.size().height() * m_ratio));
- }
- renderImage = renderImage.copy(rect);
-#endif
QFileInfo fi(fileName);
if (fi.suffix().isEmpty())
renderImage.save(fileName, "PNG");
@@ -219,16 +239,60 @@ void IconRenderer::render(const QString &fileName)
}
}
-void IconRenderer::resizeContent(int size)
+void IconRenderer::resizeContent(int dimensions)
{
- int theSize = size;
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
- if (m_ratio != 1.)
- theSize = qRound(qreal(size) / m_quickView->devicePixelRatio());
-#endif
- m_contentItem->setSize(QSizeF(theSize, theSize));
+ QSizeF size(dimensions, dimensions);
+ m_contentItem->setSize(size);
if (m_contentItem->width() > m_containerItem->width())
m_containerItem->setWidth(m_contentItem->width());
if (m_contentItem->height() > m_containerItem->height())
m_containerItem->setHeight(m_contentItem->height());
}
+
+bool IconRenderer::initRhi()
+{
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ if (!m_rhi) {
+ QQuickRenderControlPrivate *rd = QQuickRenderControlPrivate::get(m_renderControl);
+ m_rhi = rd->rhi;
+ if (!m_rhi) {
+ qWarning() << __FUNCTION__ << "Rhi is null";
+ return false;
+ }
+ }
+
+ // Don't bother deleting old ones as iconrender is a single shot executable
+ m_texTarget = nullptr;
+ m_rpDesc = nullptr;
+ m_buffer = nullptr;
+ m_texture = nullptr;
+
+ const QSize size = m_containerItem->size().toSize();
+ m_texture = m_rhi->newTexture(QRhiTexture::RGBA8, size, 1,
+ QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource);
+ if (!m_texture->create()) {
+ qWarning() << __FUNCTION__ << "QRhiTexture creation failed";
+ return false;
+ }
+
+ m_buffer = m_rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, size, 1);
+ if (!m_buffer->create()) {
+ qWarning() << __FUNCTION__ << "Depth/stencil buffer creation failed";
+ return false;
+ }
+
+ QRhiTextureRenderTargetDescription rtDesc {QRhiColorAttachment(m_texture)};
+ rtDesc.setDepthStencilBuffer(m_buffer);
+ m_texTarget = m_rhi->newTextureRenderTarget(rtDesc);
+ m_rpDesc = m_texTarget->newCompatibleRenderPassDescriptor();
+ m_texTarget->setRenderPassDescriptor(m_rpDesc);
+ if (!m_texTarget->create()) {
+ qWarning() << __FUNCTION__ << "Texture render target creation failed";
+ return false;
+ }
+
+ // redirect Qt Quick rendering into our texture
+ m_window->setRenderTarget(QQuickRenderTarget::fromRhiRenderTarget(m_texTarget));
+#endif
+ return true;
+}
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.h
index 64afed6f8a..6f5e36720d 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.h
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.h
@@ -31,8 +31,16 @@
#include <designersupportdelegate.h>
QT_BEGIN_NAMESPACE
-class QQuickView;
+class QQuickWindow;
class QQuickItem;
+#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
class IconRenderer : public QObject
@@ -44,21 +52,26 @@ public:
void setupRender();
-protected:
- bool eventFilter(QObject *watched, QEvent *event) override;
-
private:
void createIcon();
void render(const QString &fileName);
- void resizeContent(int size);
+ void resizeContent(int dimensions);
+ bool initRhi();
int m_size = 16;
- double m_ratio = 1.;
QString m_filePath;
QString m_source;
- QQuickView *m_quickView = nullptr;
+ QQuickWindow *m_window = nullptr;
QQuickItem *m_contentItem = nullptr;
QQuickItem *m_containerItem = nullptr;
DesignerSupport m_designerSupport;
bool m_is3D = false;
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ QQuickRenderControl *m_renderControl = nullptr;
+ QRhi *m_rhi = nullptr;
+ QRhiTexture *m_texture = nullptr;
+ QRhiRenderBuffer *m_buffer = nullptr;
+ QRhiTextureRenderTarget *m_texTarget = nullptr;
+ QRhiRenderPassDescriptor *m_rpDesc = nullptr;
+#endif
};
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp
index 576e53c530..8421064021 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp
@@ -87,6 +87,14 @@
#include <QtGui/qevent.h>
#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
#include <QtQuick3D/private/qquick3dnode_p.h>
#include <QtQuick3D/private/qquick3dcamera_p.h>
@@ -135,29 +143,34 @@ static bool isQuick3DMode()
return mode3D;
}
-QQuickView *Qt5InformationNodeInstanceServer::createAuxiliaryQuickView(const QUrl &url,
- QQuickItem *&rootItem)
+void Qt5InformationNodeInstanceServer::createAuxiliaryQuickView(const QUrl &url,
+ RenderViewData &viewData)
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- auto view = new QQuickView(quickView()->engine(), quickView());
- view->setFormat(quickView()->format());
- DesignerSupport::createOpenGLContext(view);
+ viewData.window = new QQuickView(quickView()->engine(), quickView());
+ viewData.window->setFormat(quickView()->format());
+ DesignerSupport::createOpenGLContext(static_cast<QQuickView *>(viewData.window));
#else
- auto view = new QQuickView(quickView()->engine(), nullptr);
- view->setFormat(quickView()->format());
+ viewData.renderControl = new QQuickRenderControl;
+ viewData.window = new QQuickWindow(viewData.renderControl);
+ viewData.renderControl->initialize();
#endif
QQmlComponent component(engine());
component.loadUrl(url);
- rootItem = qobject_cast<QQuickItem *>(component.create());
+ viewData.rootItem = qobject_cast<QQuickItem *>(component.create());
- if (!rootItem) {
+ if (!viewData.rootItem) {
qWarning() << "Could not create view for: " << url.toString() << component.errors();
- return nullptr;
+ return;
}
- DesignerSupport::setRootItem(view, rootItem);
-
- return view;
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+ DesignerSupport::setRootItem(static_cast<QQuickView *>(viewData.window), viewData.rootItem);
+#else
+ viewData.window->contentItem()->setSize(viewData.rootItem->size());
+ viewData.window->setGeometry(0, 0, viewData.rootItem->width(), viewData.rootItem->height());
+ viewData.rootItem->setParentItem(viewData.window->contentItem());
+#endif
}
void Qt5InformationNodeInstanceServer::updateLockedAndHiddenStates(const QSet<ServerNodeInstance> &instances)
@@ -177,6 +190,179 @@ void Qt5InformationNodeInstanceServer::updateLockedAndHiddenStates(const QSet<Se
}
}
+void Qt5InformationNodeInstanceServer::handleInputEvents()
+{
+ if (m_editView3DData.window) {
+ int angleDelta = 0;
+ for (int i = 0; i < m_pendingInputEventCommands.size(); ++i) {
+ const InputEventCommand &command = m_pendingInputEventCommands[i];
+ if (command.type() == QEvent::Wheel) {
+ if (i < m_pendingInputEventCommands.size() - 1) {
+ // Peek at next command. If that is also a wheel with same button/modifiers
+ // state, skip this event and add the angle delta to the next one.
+ auto nextCommand = m_pendingInputEventCommands[i + 1];
+ if (nextCommand.type() == QEvent::MouseMove
+ && nextCommand.button() == command.button()
+ && nextCommand.buttons() == command.buttons()
+ && nextCommand.modifiers() == command.modifiers()) {
+ angleDelta += command.angleDelta();
+ continue;
+ }
+ }
+ QWheelEvent *we
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
+ = new QWheelEvent(command.pos(), command.pos(), {0, 0},
+ {0, angleDelta + command.angleDelta()},
+ command.buttons(), command.modifiers(), Qt::NoScrollPhase,
+ false);
+#else
+ = new QWheelEvent(command.pos(), command.pos(), {0, 0}, {0, command.angleDelta()},
+ 0, Qt::Horizontal, command.buttons(), command.modifiers(),
+ Qt::NoScrollPhase, Qt::MouseEventNotSynthesized);
+#endif
+ angleDelta = 0;
+ QGuiApplication::sendEvent(m_editView3DData.window, we);
+ } else {
+ if (command.type() == QEvent::MouseMove && i < m_pendingInputEventCommands.size() - 1) {
+ // Peek at next command. If that is also a move with only difference being
+ // the position, skip this event as it is pointless
+ auto nextCommand = m_pendingInputEventCommands[i + 1];
+ if (nextCommand.type() == QEvent::MouseMove
+ && nextCommand.button() == command.button()
+ && nextCommand.buttons() == command.buttons()
+ && nextCommand.modifiers() == command.modifiers()) {
+ continue;
+ }
+ }
+ auto me = new QMouseEvent(command.type(), command.pos(), command.button(),
+ command.buttons(), command.modifiers());
+ // We must use sendEvent in Qt 6, as using postEvent allows the associated position
+ // data stored internally in QMutableEventPoint to potentially be updated by system
+ // before the event is delivered.
+ QGuiApplication::sendEvent(m_editView3DData.window, me);
+ }
+ }
+
+ m_pendingInputEventCommands.clear();
+
+ render3DEditView();
+ }
+}
+
+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
@@ -199,10 +385,10 @@ void Qt5InformationNodeInstanceServer::createEditView3D()
new QmlDesigner::Internal::IconGizmoImageProvider);
m_3dHelper = helper;
- m_editView3D = createAuxiliaryQuickView(QUrl("qrc:/qtquickplugin/mockfiles/EditView3D.qml"), m_editView3DRootItem);
+ createAuxiliaryQuickView(QUrl("qrc:/qtquickplugin/mockfiles/EditView3D.qml"), m_editView3DData);
- if (m_editView3DRootItem)
- helper->setParent(m_editView3DRootItem);
+ if (m_editView3DData.rootItem)
+ helper->setParent(m_editView3DData.rootItem);
#endif
}
@@ -373,10 +559,10 @@ void Qt5InformationNodeInstanceServer::handleNode3DDestroyed(QObject *obj)
{
#ifdef QUICK3D_MODULE
if (qobject_cast<QQuick3DCamera *>(obj)) {
- QMetaObject::invokeMethod(m_editView3DRootItem, "releaseCameraGizmo",
+ QMetaObject::invokeMethod(m_editView3DData.rootItem, "releaseCameraGizmo",
Q_ARG(QVariant, objectToVariant(obj)));
} else if (qobject_cast<QQuick3DAbstractLight *>(obj)) {
- QMetaObject::invokeMethod(m_editView3DRootItem, "releaseLightGizmo",
+ QMetaObject::invokeMethod(m_editView3DData.rootItem, "releaseLightGizmo",
Q_ARG(QVariant, objectToVariant(obj)));
}
removeNode3D(obj);
@@ -392,7 +578,7 @@ void Qt5InformationNodeInstanceServer::updateView3DRect(QObject *view3D)
viewPortrect = QRectF(0., 0., view3D->property("width").toDouble(),
view3D->property("height").toDouble());
}
- QQmlProperty viewPortProperty(m_editView3DRootItem, "viewPortRect", context());
+ QQmlProperty viewPortProperty(m_editView3DData.rootItem, "viewPortRect", context());
viewPortProperty.write(viewPortrect);
}
@@ -405,7 +591,7 @@ void Qt5InformationNodeInstanceServer::updateActiveSceneToEditView3D()
// Active scene change handling on qml side is async, so a deleted importScene would crash
// editView when it updates next. Disable/enable edit view update synchronously to avoid this.
QVariant activeSceneVar = objectToVariant(m_active3DScene);
- QMetaObject::invokeMethod(m_editView3DRootItem, "enableEditViewUpdate",
+ QMetaObject::invokeMethod(m_editView3DData.rootItem, "enableEditViewUpdate",
Q_ARG(QVariant, activeSceneVar));
ServerNodeInstance sceneInstance = active3DSceneInstance();
@@ -419,7 +605,7 @@ void Qt5InformationNodeInstanceServer::updateActiveSceneToEditView3D()
m_active3DSceneUpdatePending = false;
}
- QMetaObject::invokeMethod(m_editView3DRootItem, "setActiveScene", Qt::QueuedConnection,
+ QMetaObject::invokeMethod(m_editView3DData.rootItem, "setActiveScene", Qt::QueuedConnection,
Q_ARG(QVariant, activeSceneVar),
Q_ARG(QVariant, QVariant::fromValue(sceneId)));
@@ -472,11 +658,11 @@ void Qt5InformationNodeInstanceServer::resolveSceneRoots()
if (newRoot != oldRoot) {
if (qobject_cast<QQuick3DCamera *>(node)) {
- QMetaObject::invokeMethod(m_editView3DRootItem, "updateCameraGizmoScene",
+ QMetaObject::invokeMethod(m_editView3DData.rootItem, "updateCameraGizmoScene",
Q_ARG(QVariant, objectToVariant(newRoot)),
Q_ARG(QVariant, objectToVariant(node)));
} else if (qobject_cast<QQuick3DAbstractLight *>(node)) {
- QMetaObject::invokeMethod(m_editView3DRootItem, "updateLightGizmoScene",
+ QMetaObject::invokeMethod(m_editView3DData.rootItem, "updateLightGizmoScene",
Q_ARG(QVariant, objectToVariant(newRoot)),
Q_ARG(QVariant, objectToVariant(node)));
}
@@ -535,30 +721,30 @@ void Qt5InformationNodeInstanceServer::render3DEditView(int count)
void Qt5InformationNodeInstanceServer::doRender3DEditView()
{
if (m_editView3DSetupDone) {
- if (!m_editView3DContentItem)
- m_editView3DContentItem = getContentItemForRendering(m_editView3DRootItem);
+ if (!m_editView3DData.contentItem)
+ m_editView3DData.contentItem = getContentItemForRendering(m_editView3DData.rootItem);
QImage renderImage;
- updateNodesRecursive(m_editView3DContentItem);
+ updateNodesRecursive(m_editView3DData.contentItem);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
if (Internal::QuickItemNodeInstance::unifiedRenderPath()) {
- renderImage = m_editView3D->grabWindow();
+ renderImage = m_editView3DData.window->grabWindow();
} else {
// Fake render loop signaling to update things like QML items as 3D textures
- m_editView3D->beforeSynchronizing();
- m_editView3D->beforeRendering();
+ m_editView3DData.window->beforeSynchronizing();
+ m_editView3DData.window->beforeRendering();
- QSizeF size = qobject_cast<QQuickItem *>(m_editView3DContentItem)->size();
+ QSizeF size = qobject_cast<QQuickItem *>(m_editView3DData.contentItem)->size();
QRectF renderRect(QPointF(0., 0.), size);
- renderImage = designerSupport()->renderImageForItem(m_editView3DContentItem,
+ renderImage = designerSupport()->renderImageForItem(m_editView3DData.contentItem,
renderRect, size.toSize());
- m_editView3D->afterRendering();
+ m_editView3DData.window->afterRendering();
}
#else
- renderImage = m_editView3D->grabWindow();
+ renderImage = grabRenderControl(m_editView3DData);
#endif
// There's no instance related to image, so instance id is -1.
@@ -601,9 +787,9 @@ void Qt5InformationNodeInstanceServer::doRenderModelNodeImageView()
void Qt5InformationNodeInstanceServer::doRenderModelNode3DImageView()
{
#ifdef QUICK3D_MODULE
- if (m_ModelNode3DImageViewRootItem) {
- if (!m_ModelNode3DImageViewContentItem)
- m_ModelNode3DImageViewContentItem = getContentItemForRendering(m_ModelNode3DImageViewRootItem);
+ if (m_modelNode3DImageViewData.rootItem) {
+ if (!m_modelNode3DImageViewData.contentItem)
+ m_modelNode3DImageViewData.contentItem = getContentItemForRendering(m_modelNode3DImageViewData.rootItem);
// Key number is selected so that it is unlikely to conflict other ImageContainer use.
auto imgContainer = ImageContainer(m_modelNodePreviewImageCommand.instanceId(), {}, 2100000001);
@@ -628,43 +814,48 @@ void Qt5InformationNodeInstanceServer::doRenderModelNode3DImageView()
if (Internal::QuickItemNodeInstance::unifiedRenderPath()) {
// Requested size is already adjusted for target pixel ratio, so we have to adjust
// back if ratio is not default for our window.
- double ratio = m_ModelNode3DImageView->devicePixelRatio();
+ double ratio = m_modelNode3DImageViewData.window->devicePixelRatio();
renderSize.setWidth(qRound(qreal(renderSize.width()) / ratio));
renderSize.setHeight(qRound(qreal(renderSize.height()) / ratio));
}
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ m_modelNode3DImageViewData.bufferDirty = m_modelNode3DImageViewData.bufferDirty
+ || m_modelNode3DImageViewData.rootItem->width() != renderSize.width()
+ || m_modelNode3DImageViewData.rootItem->height() != renderSize.height();
+#endif
- QMetaObject::invokeMethod(m_ModelNode3DImageViewRootItem, "createViewForObject",
- Q_ARG(QVariant, objectToVariant(instanceObj)),
- Q_ARG(QVariant, QVariant::fromValue(renderSize.width())),
- Q_ARG(QVariant, QVariant::fromValue(renderSize.height())));
+ m_modelNode3DImageViewData.window->resize(renderSize);
+ m_modelNode3DImageViewData.rootItem->setSize(renderSize);
+ QMetaObject::invokeMethod(m_modelNode3DImageViewData.rootItem, "createViewForObject",
+ Q_ARG(QVariant, objectToVariant(instanceObj)));
bool ready = false;
int count = 0; // Ensure we don't ever get stuck in an infinite loop
while (!ready && ++count < 10) {
- updateNodesRecursive(m_ModelNode3DImageViewContentItem);
+ updateNodesRecursive(m_modelNode3DImageViewData.contentItem);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
if (Internal::QuickItemNodeInstance::unifiedRenderPath()) {
- renderImage = m_ModelNode3DImageView->grabWindow();
+ renderImage = m_modelNode3DImageViewData.window->grabWindow();
} else {
// Fake render loop signaling to update things like QML items as 3D textures
- m_ModelNode3DImageView->beforeSynchronizing();
- m_ModelNode3DImageView->beforeRendering();
+ m_modelNode3DImageViewData.window->beforeSynchronizing();
+ m_modelNode3DImageViewData.window->beforeRendering();
- QSizeF size = qobject_cast<QQuickItem *>(m_ModelNode3DImageViewContentItem)->size();
+ QSizeF size = qobject_cast<QQuickItem *>(m_modelNode3DImageViewData.contentItem)->size();
QRectF renderRect(QPointF(0., 0.), size);
- renderImage = designerSupport()->renderImageForItem(m_ModelNode3DImageViewContentItem,
+ renderImage = designerSupport()->renderImageForItem(m_modelNode3DImageViewData.contentItem,
renderRect, size.toSize());
- m_ModelNode3DImageView->afterRendering();
+ m_modelNode3DImageViewData.window->afterRendering();
}
#else
- renderImage = m_ModelNode3DImageView->grabWindow();
+ renderImage = grabRenderControl(m_modelNode3DImageViewData);
#endif
- QMetaObject::invokeMethod(m_ModelNode3DImageViewRootItem, "afterRender");
- ready = QQmlProperty::read(m_ModelNode3DImageViewRootItem, "ready").value<bool>();
+ QMetaObject::invokeMethod(m_modelNode3DImageViewData.rootItem, "afterRender");
+ ready = QQmlProperty::read(m_modelNode3DImageViewData.rootItem, "ready").value<bool>();
}
- QMetaObject::invokeMethod(m_ModelNode3DImageViewRootItem, "destroyView");
+ QMetaObject::invokeMethod(m_modelNode3DImageViewData.rootItem, "destroyView");
if (!m_modelNodePreviewImageCommand.componentPath().isEmpty()) {
// If component changes, puppet will need a reset anyway, so we can cache the image
m_modelNodePreviewImageCache.insert(m_modelNodePreviewImageCommand.componentPath(), renderImage);
@@ -705,9 +896,9 @@ static QRectF itemBoundingRect(QQuickItem *item)
void Qt5InformationNodeInstanceServer::doRenderModelNode2DImageView()
{
- if (m_ModelNode2DImageViewRootItem) {
- if (!m_ModelNode2DImageViewContentItem)
- m_ModelNode2DImageViewContentItem = getContentItemForRendering(m_ModelNode2DImageViewRootItem);
+ if (m_modelNode2DImageViewData.rootItem) {
+ if (!m_modelNode2DImageViewData.contentItem)
+ m_modelNode2DImageViewData.contentItem = getContentItemForRendering(m_modelNode2DImageViewData.rootItem);
// Key number is the same as in 3D case as they produce image for same purpose
auto imgContainer = ImageContainer(m_modelNodePreviewImageCommand.instanceId(), {}, 2100000001);
@@ -730,7 +921,7 @@ void Qt5InformationNodeInstanceServer::doRenderModelNode2DImageView()
return;
}
- instanceItem->setParentItem(m_ModelNode2DImageViewContentItem);
+ instanceItem->setParentItem(m_modelNode2DImageViewData.contentItem);
// Some component may expect to always be shown at certain size, so their layouts may
// not support scaling, so let's always render at the default size if item has one and
@@ -742,21 +933,28 @@ void Qt5InformationNodeInstanceServer::doRenderModelNode2DImageView()
renderSize = finalSize;
renderRect = QRectF(QPointF(0., 0.), QSizeF(renderSize));
}
- m_ModelNode2DImageView->resize(renderSize);
- m_ModelNode2DImageViewRootItem->setSize(renderSize);
- m_ModelNode2DImageViewContentItem->setPosition(QPointF(-renderRect.x(), -renderRect.y()));
- updateNodesRecursive(m_ModelNode2DImageViewContentItem);
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ m_modelNode2DImageViewData.bufferDirty = m_modelNode2DImageViewData.bufferDirty
+ || m_modelNode2DImageViewData.rootItem->width() != renderSize.width()
+ || m_modelNode2DImageViewData.rootItem->height() != renderSize.height();
+#endif
+
+ m_modelNode2DImageViewData.window->resize(renderSize);
+ m_modelNode2DImageViewData.rootItem->setSize(renderSize);
+ m_modelNode2DImageViewData.contentItem->setPosition(QPointF(-renderRect.x(), -renderRect.y()));
+
+ updateNodesRecursive(m_modelNode2DImageViewData.contentItem);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
if (Internal::QuickItemNodeInstance::unifiedRenderPath()) {
- renderImage = m_ModelNode2DImageView->grabWindow();
+ renderImage = m_modelNode2DImageViewData.window->grabWindow();
} else {
- renderImage = designerSupport()->renderImageForItem(m_ModelNode2DImageViewContentItem,
+ renderImage = designerSupport()->renderImageForItem(m_modelNode2DImageViewData.contentItem,
renderRect, renderSize);
}
#else
- renderImage = m_ModelNode2DImageView->grabWindow();
+ renderImage = grabRenderControl(m_modelNode2DImageViewData);
#endif
if (!imageHasContent(renderImage))
@@ -788,13 +986,31 @@ Qt5InformationNodeInstanceServer::Qt5InformationNodeInstanceServer(NodeInstanceC
m_propertyChangeTimer.setSingleShot(true);
m_selectionChangeTimer.setSingleShot(true);
m_render3DEditViewTimer.setSingleShot(true);
+ m_inputEventTimer.setSingleShot(true);
m_renderModelNodeImageViewTimer.setSingleShot(true);
}
Qt5InformationNodeInstanceServer::~Qt5InformationNodeInstanceServer()
{
+ m_editView3DSetupDone = false;
+
+ m_propertyChangeTimer.stop();
+ m_propertyChangeTimer.stop();
+ m_selectionChangeTimer.stop();
+ 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))
- QObject::disconnect(view, nullptr, this, nullptr);
+ view->disconnect();
+ for (auto scene : qAsConst(m_3DSceneMap))
+ scene->disconnect();
}
void Qt5InformationNodeInstanceServer::sendTokenBack()
@@ -887,29 +1103,14 @@ void Qt5InformationNodeInstanceServer::initializeAuxiliaryViews()
#ifdef QUICK3D_MODULE
if (isQuick3DMode())
createEditView3D();
- m_ModelNode3DImageView = createAuxiliaryQuickView(QUrl("qrc:/qtquickplugin/mockfiles/ModelNode3DImageView.qml"),
- m_ModelNode3DImageViewRootItem);
+ createAuxiliaryQuickView(QUrl("qrc:/qtquickplugin/mockfiles/ModelNode3DImageView.qml"),
+ m_modelNode3DImageViewData);
#endif
- m_ModelNode2DImageView = createAuxiliaryQuickView(QUrl("qrc:/qtquickplugin/mockfiles/ModelNode2DImageView.qml"),
- m_ModelNode2DImageViewRootItem);
- m_ModelNode2DImageView->setDefaultAlphaBuffer(true);
- m_ModelNode2DImageView->setColor(Qt::transparent);
-
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
- if (!m_editView3D.isNull()) {
- m_editView3D->show();
- m_editView3D->lower();
- }
- if (!m_ModelNode3DImageView.isNull()) {
- m_ModelNode3DImageView->show();
- m_ModelNode3DImageView->lower();
- }
- if (!m_ModelNode2DImageView.isNull()) {
- m_ModelNode2DImageView->show();
- m_ModelNode2DImageView->lower();
- }
-#endif
+ createAuxiliaryQuickView(QUrl("qrc:/qtquickplugin/mockfiles/ModelNode2DImageView.qml"),
+ m_modelNode2DImageViewData);
+ m_modelNode2DImageViewData.window->setDefaultAlphaBuffer(true);
+ m_modelNode2DImageViewData.window->setColor(Qt::transparent);
}
void Qt5InformationNodeInstanceServer::handleObjectPropertyChangeTimeout()
@@ -940,7 +1141,7 @@ void Qt5InformationNodeInstanceServer::createCameraAndLightGizmos(
while (cameraIt != cameras.constEnd()) {
const auto cameraObjs = cameraIt.value();
for (auto &obj : cameraObjs) {
- QMetaObject::invokeMethod(m_editView3DRootItem, "addCameraGizmo",
+ QMetaObject::invokeMethod(m_editView3DData.rootItem, "addCameraGizmo",
Q_ARG(QVariant, objectToVariant(cameraIt.key())),
Q_ARG(QVariant, objectToVariant(obj)));
}
@@ -950,7 +1151,7 @@ void Qt5InformationNodeInstanceServer::createCameraAndLightGizmos(
while (lightIt != lights.constEnd()) {
const auto lightObjs = lightIt.value();
for (auto &obj : lightObjs) {
- QMetaObject::invokeMethod(m_editView3DRootItem, "addLightGizmo",
+ QMetaObject::invokeMethod(m_editView3DData.rootItem, "addLightGizmo",
Q_ARG(QVariant, objectToVariant(lightIt.key())),
Q_ARG(QVariant, objectToVariant(obj)));
}
@@ -1134,7 +1335,7 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList<ServerNodeIns
const QHash<QString, QVariantMap> &toolStates)
{
#ifdef QUICK3D_MODULE
- if (!m_editView3DRootItem)
+ if (!m_editView3DData.rootItem)
return;
ServerNodeInstance root = rootNodeInstance();
@@ -1142,13 +1343,13 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList<ServerNodeIns
add3DViewPorts(instanceList);
add3DScenes(instanceList);
- QObject::connect(m_editView3DRootItem, SIGNAL(selectionChanged(QVariant)),
+ QObject::connect(m_editView3DData.rootItem, SIGNAL(selectionChanged(QVariant)),
this, SLOT(handleSelectionChanged(QVariant)));
- QObject::connect(m_editView3DRootItem, SIGNAL(commitObjectProperty(QVariant, QVariant)),
+ QObject::connect(m_editView3DData.rootItem, SIGNAL(commitObjectProperty(QVariant, QVariant)),
this, SLOT(handleObjectPropertyCommit(QVariant, QVariant)));
- QObject::connect(m_editView3DRootItem, SIGNAL(changeObjectProperty(QVariant, QVariant)),
+ QObject::connect(m_editView3DData.rootItem, SIGNAL(changeObjectProperty(QVariant, QVariant)),
this, SLOT(handleObjectPropertyChange(QVariant, QVariant)));
- QObject::connect(m_editView3DRootItem, SIGNAL(notifyActiveSceneChange()),
+ QObject::connect(m_editView3DData.rootItem, SIGNAL(notifyActiveSceneChange()),
this, SLOT(handleActiveSceneChange()));
QObject::connect(&m_propertyChangeTimer, &QTimer::timeout,
this, &Qt5InformationNodeInstanceServer::handleObjectPropertyChangeTimeout);
@@ -1156,6 +1357,8 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList<ServerNodeIns
this, &Qt5InformationNodeInstanceServer::handleSelectionChangeTimeout);
QObject::connect(&m_render3DEditViewTimer, &QTimer::timeout,
this, &Qt5InformationNodeInstanceServer::doRender3DEditView);
+ QObject::connect(&m_inputEventTimer, &QTimer::timeout,
+ this, &Qt5InformationNodeInstanceServer::handleInputEvents);
QString lastSceneId;
auto helper = qobject_cast<QmlDesigner::Internal::GeneralHelper *>(m_3dHelper);
@@ -1167,7 +1370,7 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList<ServerNodeIns
}
if (toolStates.contains(helper->globalStateId())) {
if (toolStates[helper->globalStateId()].contains(helper->rootSizeKey()))
- m_editView3DRootItem->setSize(toolStates[helper->globalStateId()][helper->rootSizeKey()].value<QSize>());
+ m_editView3DData.rootItem->setSize(toolStates[helper->globalStateId()][helper->rootSizeKey()].value<QSize>());
if (toolStates[helper->globalStateId()].contains(helper->lastSceneIdKey()))
lastSceneId = toolStates[helper->globalStateId()][helper->lastSceneIdKey()].toString();
}
@@ -1198,7 +1401,7 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList<ServerNodeIns
if (toolStates.contains({})) {
// Update tool state to an existing no-scene state before updating the active scene to
// ensure the previous state is inherited properly in all cases.
- QMetaObject::invokeMethod(m_editView3DRootItem, "updateToolStates", Qt::QueuedConnection,
+ QMetaObject::invokeMethod(m_editView3DData.rootItem, "updateToolStates", Qt::QueuedConnection,
Q_ARG(QVariant, toolStates[{}]),
Q_ARG(QVariant, QVariant::fromValue(false)));
}
@@ -1456,13 +1659,13 @@ void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionComm
// Ensure the UI has enough selection box items. If it doesn't yet have them, which can be the
// case when the first selection processed is a multiselection, we wait a bit as
// using the new boxes immediately leads to visual glitches.
- int boxCount = m_editView3DRootItem->property("selectionBoxes").value<QVariantList>().size();
+ int boxCount = m_editView3DData.rootItem->property("selectionBoxes").value<QVariantList>().size();
if (boxCount < selectedObjs.size()) {
- QMetaObject::invokeMethod(m_editView3DRootItem, "ensureSelectionBoxes",
+ QMetaObject::invokeMethod(m_editView3DData.rootItem, "ensureSelectionBoxes",
Q_ARG(QVariant, QVariant::fromValue(selectedObjs.size())));
m_selectionChangeTimer.start(0);
} else {
- QMetaObject::invokeMethod(m_editView3DRootItem, "selectObjects",
+ QMetaObject::invokeMethod(m_editView3DData.rootItem, "selectObjects",
Q_ARG(QVariant, QVariant::fromValue(selectedObjs)));
}
@@ -1511,27 +1714,10 @@ void Qt5InformationNodeInstanceServer::removeInstances(const RemoveInstancesComm
void Qt5InformationNodeInstanceServer::inputEvent(const InputEventCommand &command)
{
- if (m_editView3D) {
- if (command.type() == QEvent::Wheel) {
- QWheelEvent *we
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
- = new QWheelEvent(command.pos(), command.pos(), {0, 0}, {0, command.angleDelta()},
- command.buttons(), command.modifiers(), Qt::NoScrollPhase,
- false);
-#else
- = new QWheelEvent(command.pos(), command.pos(), {0, 0}, {0, command.angleDelta()},
- 0, Qt::Horizontal, command.buttons(), command.modifiers(),
- Qt::NoScrollPhase, Qt::MouseEventNotSynthesized);
-#endif
-
- QGuiApplication::postEvent(m_editView3D, we);
- } else {
- auto me = new QMouseEvent(command.type(), command.pos(), command.button(),
- command.buttons(), command.modifiers());
- QGuiApplication::postEvent(m_editView3D, me);
- }
-
- render3DEditView();
+ if (m_editView3DData.window) {
+ m_pendingInputEventCommands.append(command);
+ if (!m_inputEventTimer.isActive())
+ m_inputEventTimer.start(0);
}
}
@@ -1554,7 +1740,7 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c
updatedState.insert("transformMode", 2);
break;
case View3DActionCommand::FitToView:
- QMetaObject::invokeMethod(m_editView3DRootItem, "fitToView");
+ QMetaObject::invokeMethod(m_editView3DData.rootItem, "fitToView");
break;
case View3DActionCommand::SelectionModeToggle:
updatedState.insert("selectionMode", command.isEnabled() ? 1 : 0);
@@ -1578,7 +1764,7 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c
}
if (!updatedState.isEmpty()) {
- QMetaObject::invokeMethod(m_editView3DRootItem, "updateToolStates",
+ QMetaObject::invokeMethod(m_editView3DData.rootItem, "updateToolStates",
Q_ARG(QVariant, updatedState),
Q_ARG(QVariant, QVariant::fromValue(false)));
}
@@ -1619,7 +1805,7 @@ void Qt5InformationNodeInstanceServer::changeIds(const ChangeIdsCommand &command
qint32 sceneInstanceId = sceneInstance.instanceId();
for (const auto &id : command.ids) {
if (sceneInstanceId == id.instanceId()) {
- QMetaObject::invokeMethod(m_editView3DRootItem, "handleActiveSceneIdChange",
+ QMetaObject::invokeMethod(m_editView3DData.rootItem, "handleActiveSceneIdChange",
Qt::QueuedConnection,
Q_ARG(QVariant, QVariant(sceneInstance.id())));
render3DEditView();
@@ -1763,12 +1949,18 @@ void Qt5InformationNodeInstanceServer::update3DViewState(const Update3dViewState
#ifdef QUICK3D_MODULE
if (command.type() == Update3dViewStateCommand::SizeChange) {
if (m_editView3DSetupDone) {
- m_editView3DRootItem->setSize(command.size());
+ m_editView3DData.rootItem->setSize(command.size());
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ m_editView3DData.window->contentItem()->setSize(m_editView3DData.rootItem->size());
+ m_editView3DData.window->setGeometry(0, 0, m_editView3DData.rootItem->width(),
+ m_editView3DData.rootItem->height());
+ m_editView3DData.bufferDirty = true;
+#endif
auto helper = qobject_cast<QmlDesigner::Internal::GeneralHelper *>(m_3dHelper);
if (helper)
helper->storeToolState(helper->globalStateId(), helper->rootSizeKey(), QVariant(command.size()), 0);
- // Queue two renders to make sure icon gizmos update properly
- render3DEditView(2);
+ // Queue three renders to make sure icon gizmos update properly
+ render3DEditView(3);
}
}
#else
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h
index f703e9fcb8..47dacd45db 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h
@@ -39,6 +39,15 @@
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 {
@@ -129,19 +138,33 @@ private:
void doRenderModelNodeImageView();
void doRenderModelNode3DImageView();
void doRenderModelNode2DImageView();
- QQuickView *createAuxiliaryQuickView(const QUrl &url, QQuickItem *&rootItem);
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;
+ RenderViewData m_modelNode3DImageViewData;
+ RenderViewData m_modelNode2DImageViewData;
- QPointer<QQuickView> m_editView3D;
- QQuickItem *m_editView3DRootItem = nullptr;
- QQuickItem *m_editView3DContentItem = nullptr;
bool m_editView3DSetupDone = false;
- QPointer<QQuickView> m_ModelNode3DImageView;
- QQuickItem *m_ModelNode3DImageViewRootItem = nullptr;
- QQuickItem *m_ModelNode3DImageViewContentItem = nullptr;
- QPointer<QQuickView> m_ModelNode2DImageView;
- QQuickItem *m_ModelNode2DImageViewRootItem = nullptr;
- QQuickItem *m_ModelNode2DImageViewContentItem = nullptr;
RequestModelNodePreviewImageCommand m_modelNodePreviewImageCommand;
QHash<QString, QImage> m_modelNodePreviewImageCache;
QSet<QObject *> m_view3Ds;
@@ -156,9 +179,11 @@ private:
QTimer m_selectionChangeTimer;
QTimer m_render3DEditViewTimer;
QTimer m_renderModelNodeImageViewTimer;
+ QTimer m_inputEventTimer;
QVariant m_changedNode;
PropertyName m_changedProperty;
ChangeSelectionCommand m_lastSelectionChangeCommand;
+ QList<InputEventCommand> m_pendingInputEventCommands;
QObject *m_3dHelper = nullptr;
int m_need3DEditViewRender = 0;
};