aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/quick/quickwidgets/qquickviewcomparison/main.cpp3
-rw-r--r--examples/quick/quickwidgets/qquickviewcomparison/mainwindow.cpp2
-rw-r--r--examples/quick/quickwidgets/quickwidget/main.cpp3
-rw-r--r--src/quickwidgets/qquickwidget.cpp120
-rw-r--r--src/quickwidgets/qquickwidget_p.h1
-rw-r--r--tests/auto/.prev_CMakeLists.txt3
-rw-r--r--tests/auto/CMakeLists.txt3
-rw-r--r--tests/auto/auto.pro4
-rw-r--r--tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp9
9 files changed, 102 insertions, 46 deletions
diff --git a/examples/quick/quickwidgets/qquickviewcomparison/main.cpp b/examples/quick/quickwidgets/qquickviewcomparison/main.cpp
index 73db97eddb..f1fe397462 100644
--- a/examples/quick/quickwidgets/qquickviewcomparison/main.cpp
+++ b/examples/quick/quickwidgets/qquickviewcomparison/main.cpp
@@ -60,6 +60,9 @@ int main(int argc, char **argv)
QApplication app(argc, argv);
+ // this example and QQuickWidget are only functional when rendering with OpenGL
+ QQuickWindow::setSceneGraphBackend(QSGRendererInterface::OpenGLRhi);
+
QCoreApplication::setApplicationName("Qt QQuickView/QQuickWidget Comparison Example");
QCoreApplication::setOrganizationName("QtProject");
QCoreApplication::setApplicationVersion(QT_VERSION_STR);
diff --git a/examples/quick/quickwidgets/qquickviewcomparison/mainwindow.cpp b/examples/quick/quickwidgets/qquickviewcomparison/mainwindow.cpp
index 850ecd147b..2e45bc2df6 100644
--- a/examples/quick/quickwidgets/qquickviewcomparison/mainwindow.cpp
+++ b/examples/quick/quickwidgets/qquickviewcomparison/mainwindow.cpp
@@ -179,8 +179,8 @@ void MainWindow::updateView()
connect(quickWidget, &QQuickWidget::statusChanged, this, &MainWindow::onStatusChangedWidget);
connect(quickWidget, &QQuickWidget::sceneGraphError, this, &MainWindow::onSceneGraphError);
quickWidget->setSource(source);
- m_currentRootObject = quickWidget->rootObject();
switchTo(quickWidget);
+ m_currentRootObject = quickWidget->rootObject();
}
if (m_currentRootObject) {
diff --git a/examples/quick/quickwidgets/quickwidget/main.cpp b/examples/quick/quickwidgets/quickwidget/main.cpp
index f28b2f1443..3bff5901f9 100644
--- a/examples/quick/quickwidgets/quickwidget/main.cpp
+++ b/examples/quick/quickwidgets/quickwidget/main.cpp
@@ -197,6 +197,9 @@ int main(int argc, char **argv)
{
QApplication app(argc, argv);
+ // this example and QQuickWidget are only functional when rendering with OpenGL
+ QQuickWindow::setSceneGraphBackend(QSGRendererInterface::OpenGLRhi);
+
QCoreApplication::setApplicationName("Qt QQuickWidget Example");
QCoreApplication::setOrganizationName("QtProject");
QCoreApplication::setApplicationVersion(QT_VERSION_STR);
diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp
index f3d26e4a73..221bdfaee6 100644
--- a/src/quickwidgets/qquickwidget.cpp
+++ b/src/quickwidgets/qquickwidget.cpp
@@ -44,6 +44,7 @@
#include "private/qquickitem_p.h"
#include "private/qquickitemchangelistener_p.h"
#include "private/qquickrendercontrol_p.h"
+#include "private/qsgrhisupport_p.h"
#include "private/qsgsoftwarerenderer_p.h"
@@ -75,6 +76,9 @@
# include <QtCore/qt_windows.h>
#endif
+#include <QtQuick/qquickgraphicsdevice.h>
+#include <QtQuick/qquickrendertarget.h>
+
QT_BEGIN_NAMESPACE
// override setVisble to prevent accidental offscreen window being created
@@ -102,16 +106,25 @@ private:
QQuickWidget *m_quickWidget;
};
-void QQuickWidgetPrivate::init(QQmlEngine* e)
+void QQuickWidgetPrivate::initOffscreenWindow()
{
Q_Q(QQuickWidget);
-
- renderControl = new QQuickWidgetRenderControl(q);
- offscreenWindow = new QQuickWindow(*new QQuickOffcreenWindowPrivate(),renderControl);
+ offscreenWindow = new QQuickWindow(*new QQuickOffcreenWindowPrivate(), renderControl);
offscreenWindow->setTitle(QString::fromLatin1("Offscreen"));
offscreenWindow->setObjectName(QString::fromLatin1("QQuickOffScreenWindow"));
// Do not call create() on offscreenWindow.
+ QWidget::connect(offscreenWindow, SIGNAL(sceneGraphInitialized()), q, SLOT(createFramebufferObject()));
+ QWidget::connect(offscreenWindow, SIGNAL(sceneGraphInvalidated()), q, SLOT(destroyFramebufferObject()));
+}
+
+void QQuickWidgetPrivate::init(QQmlEngine* e)
+{
+ Q_Q(QQuickWidget);
+
+ renderControl = new QQuickWidgetRenderControl(q);
+ initOffscreenWindow();
+
// Check if the Software Adaptation is being used
auto sgRendererInterface = offscreenWindow->rendererInterface();
if (sgRendererInterface && sgRendererInterface->graphicsApi() == QSGRendererInterface::Software)
@@ -126,6 +139,9 @@ void QQuickWidgetPrivate::init(QQmlEngine* e)
qWarning("QQuickWidget is not supported on this platform.");
}
+ if (QSGRhiSupport::instance()->rhiBackend() != QRhi::OpenGLES2)
+ qWarning("QQuickWidget is only supported on OpenGL. Use QQuickWindow::setSceneGraphBackend() to override the default.");
+
engine = e;
if (!engine.isNull() && !engine.data()->incubationController())
@@ -135,8 +151,6 @@ void QQuickWidgetPrivate::init(QQmlEngine* e)
q->setAcceptDrops(true);
#endif
- QWidget::connect(offscreenWindow, SIGNAL(sceneGraphInitialized()), q, SLOT(createFramebufferObject()));
- QWidget::connect(offscreenWindow, SIGNAL(sceneGraphInvalidated()), q, SLOT(destroyFramebufferObject()));
QObject::connect(renderControl, SIGNAL(renderRequested()), q, SLOT(triggerUpdate()));
QObject::connect(renderControl, SIGNAL(sceneChanged()), q, SLOT(triggerUpdate()));
}
@@ -181,18 +195,28 @@ void QQuickWidgetPrivate::invalidateRenderControl()
void QQuickWidgetPrivate::handleWindowChange()
{
+ Q_Q(QQuickWidget);
+
if (offscreenWindow->isPersistentSceneGraph() && qGuiApp->testAttribute(Qt::AA_ShareOpenGLContexts))
return;
// In case of !isPersistentSceneGraph or when we need a new context due to
// the need to share resources with the new window's context, we must both
- // invalidate the scenegraph and destroy the context. With
- // QQuickRenderControl destroying the context must be preceded by an
- // invalidate to prevent being left with dangling context references in the
- // rendercontrol.
+ // invalidate the scenegraph and destroy the context. QQuickRenderControl
+ // must be recreated because its RHI will contain a dangling pointer to
+ // the context.
- invalidateRenderControl();
+ delete offscreenWindow;
+ offscreenWindow = nullptr;
+ delete renderControl;
+ renderControl = new QQuickWidgetRenderControl(q);
+ initOffscreenWindow();
+
+ QObject::connect(renderControl, SIGNAL(renderRequested()), q, SLOT(triggerUpdate()));
+ QObject::connect(renderControl, SIGNAL(sceneChanged()), q, SLOT(triggerUpdate()));
+
+ execute();
if (!useSoftwareRenderer)
destroyContext();
}
@@ -230,10 +254,10 @@ QQuickWidgetPrivate::~QQuickWidgetPrivate()
#if QT_CONFIG(opengl)
// context and offscreenSurface are current at this stage, if the context was created.
Q_ASSERT(!context || (QOpenGLContext::currentContext() == context && context->surface() == offscreenSurface));
- delete renderControl; // always delete the rendercontrol first
- delete offscreenWindow;
delete resolvedFbo;
delete fbo;
+ delete offscreenWindow;
+ delete renderControl;
destroyContext();
#endif
@@ -302,6 +326,8 @@ void QQuickWidgetPrivate::render(bool needsSync)
QOpenGLContextPrivate::get(context)->defaultFboRedirect = fbo->handle();
+ renderControl->beginFrame();
+
if (needsSync) {
renderControl->polishItems();
renderControl->sync();
@@ -309,6 +335,9 @@ void QQuickWidgetPrivate::render(bool needsSync)
renderControl->render();
+ renderControl->endFrame();
+
+ context->makeCurrent(offscreenSurface);
if (resolvedFbo) {
QRect rect(QPoint(0, 0), fbo->size());
QOpenGLFramebufferObject::blitFramebuffer(resolvedFbo, rect, fbo, rect);
@@ -349,7 +378,6 @@ void QQuickWidgetPrivate::renderSceneGraph()
return;
if (!useSoftwareRenderer) {
- QOpenGLContext *context = offscreenWindow->openglContext();
if (!context) {
qWarning("QQuickWidget: Attempted to render scene with no context");
return;
@@ -383,7 +411,13 @@ QImage QQuickWidgetPrivate::grabFramebuffer()
context->makeCurrent(offscreenSurface);
#endif
}
- return offscreenWindow->grabWindow();
+
+
+ // grabWindow() does not work for the OpenGL + render control case, so we
+ // prefer the FBO's toImage() if available. When the software renderer
+ // is in use, however, there will be no FBO and we fall back to grabWindow()
+ // instead.
+ return fbo != nullptr ? fbo->toImage() : offscreenWindow->grabWindow();
}
// Intentionally not overriding the QQuickWindow's focusObject.
@@ -894,7 +928,7 @@ void QQuickWidgetPrivate::createContext()
// On hide-show we may invalidate() (when !isPersistentSceneGraph) but our
// context is kept. We may need to initialize() again, though.
- const bool reinit = context && !offscreenWindow->openglContext();
+ const bool reinit = context && !offscreenWindow->isSceneGraphInitialized();
if (!reinit) {
if (context)
@@ -929,8 +963,10 @@ void QQuickWidgetPrivate::createContext()
}
if (context->makeCurrent(offscreenSurface)) {
- if (!offscreenWindow->openglContext())
- renderControl->initialize(context);
+ if (!offscreenWindow->isSceneGraphInitialized()) {
+ offscreenWindow->setGraphicsDevice(QQuickGraphicsDevice::fromOpenGLContext(context));
+ renderControl->initialize();
+ }
} else
#endif
qWarning("QQuickWidget: Failed to make context current");
@@ -971,30 +1007,28 @@ void QQuickWidget::createFramebufferObject()
}
#if QT_CONFIG(opengl)
- QOpenGLContext *context = d->offscreenWindow->openglContext();
-
- if (!context) {
+ if (!d->context) {
qWarning("QQuickWidget: Attempted to create FBO with no context");
return;
}
QOpenGLContext *shareWindowContext = QWidgetPrivate::get(window())->shareContext();
- if (shareWindowContext && context->shareContext() != shareWindowContext && !qGuiApp->testAttribute(Qt::AA_ShareOpenGLContexts)) {
- context->setShareContext(shareWindowContext);
- context->setScreen(shareWindowContext->screen());
- if (!context->create())
+ if (shareWindowContext && d->context->shareContext() != shareWindowContext && !qGuiApp->testAttribute(Qt::AA_ShareOpenGLContexts)) {
+ d->context->setShareContext(shareWindowContext);
+ d->context->setScreen(shareWindowContext->screen());
+ if (!d->context->create())
qWarning("QQuickWidget: Failed to recreate context");
// The screen may be different so we must recreate the offscreen surface too.
// Unlike QOpenGLContext, QOffscreenSurface's create() does not recreate so have to destroy() first.
d->offscreenSurface->destroy();
- d->offscreenSurface->setScreen(context->screen());
+ d->offscreenSurface->setScreen(d->context->screen());
d->offscreenSurface->create();
}
- context->makeCurrent(d->offscreenSurface);
+ d->context->makeCurrent(d->offscreenSurface);
int samples = d->requestedSamples;
- if (!QOpenGLExtensions(context).hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample))
+ if (!QOpenGLExtensions(d->context).hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample))
samples = 0;
QOpenGLFramebufferObjectFormat format;
@@ -1004,11 +1038,12 @@ void QQuickWidget::createFramebufferObject()
// The default framebuffer for normal windows have sRGB support on OS X which leads to the Qt Quick text item
// utilizing sRGB blending. To get identical results with QQuickWidget we have to have our framebuffer backed
// by an sRGB texture.
-#ifdef Q_OS_OSX
- if (context->hasExtension("GL_ARB_framebuffer_sRGB")
- && context->hasExtension("GL_EXT_texture_sRGB")
- && context->hasExtension("GL_EXT_texture_sRGB_decode"))
+#ifdef Q_OS_MACOS
+ if (d->context->hasExtension("GL_ARB_framebuffer_sRGB")
+ && d->context->hasExtension("GL_EXT_texture_sRGB")
+ && d->context->hasExtension("GL_EXT_texture_sRGB_decode")) {
format.setInternalTextureFormat(GL_SRGB8_ALPHA8_EXT);
+ }
#endif
const QSize fboSize = size() * devicePixelRatioF();
@@ -1022,15 +1057,18 @@ void QQuickWidget::createFramebufferObject()
// When compositing in the backingstore, sampling the sRGB texture would perform an
// sRGB-linear conversion which is not what we want when the final framebuffer (the window's)
// is sRGB too. Disable the conversion.
-#ifdef Q_OS_OSX
+#ifdef Q_OS_MACOS
if (format.internalTextureFormat() == GL_SRGB8_ALPHA8_EXT) {
- QOpenGLFunctions *funcs = context->functions();
+ QOpenGLFunctions *funcs = d->context->functions();
funcs->glBindTexture(GL_TEXTURE_2D, d->fbo->texture());
funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
}
#endif
- d->offscreenWindow->setRenderTarget(d->fbo);
+ GLuint textureId = d->fbo->texture();
+ d->offscreenWindow->setRenderTarget( QQuickRenderTarget::fromNativeTexture({ textureId, 0 }, fboSize, samples));
+
+ d->renderControl->setSamples(samples);
if (samples > 0)
d->resolvedFbo = new QOpenGLFramebufferObject(fboSize);
@@ -1247,7 +1285,7 @@ void QQuickWidget::resizeEvent(QResizeEvent *e)
if (d->context) {
// Bail out when receiving a resize after scenegraph invalidation. This can happen
// during hide - resize - show sequences and also during application exit.
- if (!d->fbo && !d->offscreenWindow->openglContext())
+ if (!d->fbo && !d->offscreenWindow->isSceneGraphInitialized())
return;
if (!d->fbo || d->fbo->size() != size() * devicePixelRatioF()) {
needsSync = true;
@@ -1260,8 +1298,7 @@ void QQuickWidget::resizeEvent(QResizeEvent *e)
d->createContext();
}
- QOpenGLContext *context = d->offscreenWindow->openglContext();
- if (!context) {
+ if (!d->context) {
qWarning("QQuickWidget::resizeEvent() no OpenGL context");
return;
}
@@ -1351,7 +1388,7 @@ void QQuickWidget::showEvent(QShowEvent *)
if (!d->useSoftwareRenderer) {
d->createContext();
- if (d->offscreenWindow->openglContext()) {
+ if (d->offscreenWindow->isSceneGraphInitialized()) {
shouldTriggerUpdate = false;
d->render(true);
// render() may have led to a QQuickWindow::update() call (for
@@ -1707,6 +1744,11 @@ void QQuickWidget::setClearColor(const QColor &color)
\warning Use the return value of this function with caution. In
particular, do not ever attempt to show the QQuickWindow, and be
very careful when using other QWindow-only APIs.
+
+ \warning The offscreen window may be deleted (and recreated) during
+ the life time of the QQuickWidget, particularly when the widget is
+ moved to another QQuickWindow. If you need to know when the window
+ has been replaced, connect to its destroyed() signal.
*/
QQuickWindow *QQuickWidget::quickWindow() const
{
diff --git a/src/quickwidgets/qquickwidget_p.h b/src/quickwidgets/qquickwidget_p.h
index 881f7f9220..0517a772e1 100644
--- a/src/quickwidgets/qquickwidget_p.h
+++ b/src/quickwidgets/qquickwidget_p.h
@@ -108,6 +108,7 @@ public:
#endif
void init(QQmlEngine* e = 0);
+ void initOffscreenWindow();
void ensureEngine() const;
void handleWindowChange();
void invalidateRenderControl();
diff --git a/tests/auto/.prev_CMakeLists.txt b/tests/auto/.prev_CMakeLists.txt
index 9ec371359b..c52566a954 100644
--- a/tests/auto/.prev_CMakeLists.txt
+++ b/tests/auto/.prev_CMakeLists.txt
@@ -13,3 +13,6 @@ endif()
if(TARGET Qt::Gui AND (QT_FEATURE_opengl OR QT_FEATURE_opengles2 OR QT_FEATURE_opengles3))
add_subdirectory(particles)
endif()
+if(TARGET Qt::Gui AND TARGET Qt::Widgets AND (QT_FEATURE_opengl OR QT_FEATURE_opengles2 OR QT_FEATURE_opengles3))
+ add_subdirectory(quickwidgets)
+endif()
diff --git a/tests/auto/CMakeLists.txt b/tests/auto/CMakeLists.txt
index 222c735359..eb1c2d34df 100644
--- a/tests/auto/CMakeLists.txt
+++ b/tests/auto/CMakeLists.txt
@@ -15,3 +15,6 @@ endif()
if(TARGET Qt::Gui AND (QT_FEATURE_opengl OR QT_FEATURE_opengles2 OR QT_FEATURE_opengles3))
add_subdirectory(particles)
endif()
+if(TARGET Qt::Gui AND TARGET Qt::Widgets AND (QT_FEATURE_opengl OR QT_FEATURE_opengles2 OR QT_FEATURE_opengles3))
+ add_subdirectory(quickwidgets)
+endif()
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
index 2a22868390..d967b01d61 100644
--- a/tests/auto/auto.pro
+++ b/tests/auto/auto.pro
@@ -11,9 +11,7 @@ SUBDIRS=\
qtHaveModule(gui):qtConfig(opengl(es1|es2)?) {
SUBDIRS += particles
-# Disabled for Qt 6 until a conclusion on QQuickWidget is reached
-# qtHaveModule(widgets): SUBDIRS += quickwidgets
-
+ qtHaveModule(widgets): SUBDIRS += quickwidgets
}
# console applications not supported
diff --git a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
index 8211400262..b47837179a 100644
--- a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
+++ b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
@@ -152,6 +152,7 @@ private:
tst_qquickwidget::tst_qquickwidget()
{
+ QQuickWindow::setSceneGraphBackend(QSGRendererInterface::OpenGLRhi);
}
void tst_qquickwidget::showHide()
@@ -379,8 +380,8 @@ void tst_qquickwidget::readback()
QImage img = view->grabFramebuffer();
QVERIFY(!img.isNull());
- QCOMPARE(img.width(), view->width());
- QCOMPARE(img.height(), view->height());
+ QCOMPARE(img.width(), qCeil(view->width() * view->devicePixelRatioF()));
+ QCOMPARE(img.height(), qCeil(view->height() * view->devicePixelRatioF()));
QRgb pix = img.pixel(5, 5);
QCOMPARE(pix, qRgb(255, 0, 0));
@@ -447,13 +448,15 @@ void tst_qquickwidget::reparentToNewWindow()
window2.show();
QVERIFY(QTest::qWaitForWindowExposed(&window2));
- QSignalSpy afterRenderingSpy(qqw->quickWindow(), &QQuickWindow::afterRendering);
qqw->setParent(&window2);
+
+ QSignalSpy afterRenderingSpy(qqw->quickWindow(), &QQuickWindow::afterRendering);
qqw->show();
QTRY_VERIFY(afterRenderingSpy.size() > 0);
QImage img = qqw->grabFramebuffer();
+
QCOMPARE(img.pixel(5, 5), qRgb(255, 0, 0));
}