From 62198ab4485e15f350122770d5dfd8de7e59b8f9 Mon Sep 17 00:00:00 2001 From: Andy Nichols Date: Tue, 19 Apr 2016 16:19:23 +0200 Subject: QQuickWidget: Enable use with software renderer backend Change-Id: Ic7a550e55cc4ece4c3a5547dae5bf0dbb3f5b0ac Reviewed-by: Laszlo Agocs --- .../adaptations/software/qsgsoftwarerenderer_p.h | 2 +- src/quickwidgets/qquickwidget.cpp | 224 ++++++++++++++------- src/quickwidgets/qquickwidget.h | 37 ++-- src/quickwidgets/qquickwidget_p.h | 3 + 4 files changed, 177 insertions(+), 89 deletions(-) (limited to 'src') diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer_p.h index bc059438f4..e2b8bcddca 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer_p.h @@ -57,7 +57,7 @@ QT_BEGIN_NAMESPACE class QPaintDevice; -class QSGSoftwareRenderer : public QSGAbstractSoftwareRenderer +class Q_QUICK_PRIVATE_EXPORT QSGSoftwareRenderer : public QSGAbstractSoftwareRenderer { public: QSGSoftwareRenderer(QSGRenderContext *context); diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp index 0a10ec5e9c..bd4a34fdb8 100644 --- a/src/quickwidgets/qquickwidget.cpp +++ b/src/quickwidgets/qquickwidget.cpp @@ -45,6 +45,8 @@ #include "private/qquickitemchangelistener_p.h" #include "private/qquickrendercontrol_p.h" +#include "private/qsgsoftwarerenderer_p.h" + #include #include #include @@ -60,6 +62,9 @@ #include #include #include +#include + +#include #ifdef Q_OS_WIN # include @@ -93,10 +98,17 @@ void QQuickWidgetPrivate::init(QQmlEngine* e) offscreenWindow->setTitle(QString::fromLatin1("Offscreen")); // Do not call create() on offscreenWindow. - if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::RasterGLSurface)) - setRenderToTexture(); - else - qWarning("QQuickWidget is not supported on this platform."); + // Check if the Software Adaptation is being used + auto sgRendererInterface = offscreenWindow->rendererInterface(); + if (sgRendererInterface && sgRendererInterface->graphicsAPI() == QSGRendererInterface::Software) + useSoftwareRenderer = true; + + if (!useSoftwareRenderer) { + if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::RasterGLSurface)) + setRenderToTexture(); + else + qWarning("QQuickWidget is not supported on this platform."); + } engine = e; @@ -118,13 +130,15 @@ void QQuickWidgetPrivate::init(QQmlEngine* e) void QQuickWidgetPrivate::invalidateRenderControl() { - if (!context) // this is not an error, could be called before creating the context, or multiple times - return; + if (!useSoftwareRenderer) { + if (!context) // this is not an error, could be called before creating the context, or multiple times + return; - bool success = context->makeCurrent(offscreenSurface); - if (!success) { - qWarning("QQuickWidget::invalidateRenderControl could not make context current"); - return; + bool success = context->makeCurrent(offscreenSurface); + if (!success) { + qWarning("QQuickWidget::invalidateRenderControl could not make context current"); + return; + } } renderControl->invalidate(); @@ -133,7 +147,8 @@ void QQuickWidgetPrivate::invalidateRenderControl() void QQuickWidgetPrivate::handleWindowChange() { invalidateRenderControl(); - destroyContext(); + if (!useSoftwareRenderer) + destroyContext(); } QQuickWidgetPrivate::QQuickWidgetPrivate() @@ -151,6 +166,7 @@ QQuickWidgetPrivate::QQuickWidgetPrivate() , updatePending(false) , fakeHidden(false) , requestedSamples(0) + , useSoftwareRenderer(false) { } @@ -158,14 +174,19 @@ QQuickWidgetPrivate::~QQuickWidgetPrivate() { invalidateRenderControl(); - // 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; - - destroyContext(); + if (useSoftwareRenderer) { + delete renderControl; + delete offscreenWindow; + } else { + // 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; + + destroyContext(); + } } void QQuickWidgetPrivate::execute() @@ -206,37 +227,53 @@ void QQuickWidgetPrivate::itemGeometryChanged(QQuickItem *resizeItem, const QRec QQuickItemChangeListener::itemGeometryChanged(resizeItem, newGeometry, oldGeometry); } +// Is never called when using the software renderer void QQuickWidgetPrivate::render(bool needsSync) { - // createFramebufferObject() bails out when the size is empty. In this case - // we cannot render either. - if (!fbo) - return; + if (!useSoftwareRenderer) { + // createFramebufferObject() bails out when the size is empty. In this case + // we cannot render either. + if (!fbo) + return; - Q_ASSERT(context); + Q_ASSERT(context); - if (!context->makeCurrent(offscreenSurface)) { - qWarning("QQuickWidget: Cannot render due to failing makeCurrent()"); - return; - } + if (!context->makeCurrent(offscreenSurface)) { + qWarning("QQuickWidget: Cannot render due to failing makeCurrent()"); + return; + } - QOpenGLContextPrivate::get(context)->defaultFboRedirect = fbo->handle(); + QOpenGLContextPrivate::get(context)->defaultFboRedirect = fbo->handle(); - if (needsSync) { - renderControl->polishItems(); - renderControl->sync(); - } + if (needsSync) { + renderControl->polishItems(); + renderControl->sync(); + } - renderControl->render(); + renderControl->render(); - if (resolvedFbo) { - QRect rect(QPoint(0, 0), fbo->size()); - QOpenGLFramebufferObject::blitFramebuffer(resolvedFbo, rect, fbo, rect); - } + if (resolvedFbo) { + QRect rect(QPoint(0, 0), fbo->size()); + QOpenGLFramebufferObject::blitFramebuffer(resolvedFbo, rect, fbo, rect); + } - static_cast(context->functions())->flushShared(); + static_cast(context->functions())->flushShared(); - QOpenGLContextPrivate::get(context)->defaultFboRedirect = 0; + QOpenGLContextPrivate::get(context)->defaultFboRedirect = 0; + } else { + //Software Renderer + if (needsSync) { + renderControl->polishItems(); + renderControl->sync(); + } + + QQuickWindowPrivate *cd = QQuickWindowPrivate::get(offscreenWindow); + auto softwareRenderer = static_cast(cd->renderer); + if (softwareRenderer) { + softwareRenderer->setCurrentPaintDevice(&softwareImage); + renderControl->render(); + } + } } void QQuickWidgetPrivate::renderSceneGraph() @@ -247,13 +284,15 @@ void QQuickWidgetPrivate::renderSceneGraph() if (!q->isVisible() || fakeHidden) return; - QOpenGLContext *context = offscreenWindow->openglContext(); - if (!context) { - qWarning("QQuickWidget: Attempted to render scene with no context"); - return; - } + if (!useSoftwareRenderer) { + QOpenGLContext *context = offscreenWindow->openglContext(); + if (!context) { + qWarning("QQuickWidget: Attempted to render scene with no context"); + return; + } - Q_ASSERT(offscreenSurface); + Q_ASSERT(offscreenSurface); + } render(true); @@ -267,10 +306,12 @@ void QQuickWidgetPrivate::renderSceneGraph() QImage QQuickWidgetPrivate::grabFramebuffer() { - if (!context) - return QImage(); + if (!useSoftwareRenderer) { + if (!context) + return QImage(); - context->makeCurrent(offscreenSurface); + context->makeCurrent(offscreenSurface); + } return renderControl->grab(); } @@ -377,6 +418,7 @@ QQuickWidget::QQuickWidget(QWidget *parent) { setMouseTracking(true); setFocusPolicy(Qt::StrongFocus); + setAttribute(Qt::WA_OpaquePaintEvent, true); d_func()->init(); } @@ -390,6 +432,7 @@ QQuickWidget::QQuickWidget(const QUrl &source, QWidget *parent) { setMouseTracking(true); setFocusPolicy(Qt::StrongFocus); + setAttribute(Qt::WA_OpaquePaintEvent, true); d_func()->init(); setSource(source); } @@ -408,6 +451,7 @@ QQuickWidget::QQuickWidget(QQmlEngine* engine, QWidget *parent) { setMouseTracking(true); setFocusPolicy(Qt::StrongFocus); + setAttribute(Qt::WA_OpaquePaintEvent, true); Q_ASSERT(engine); d_func()->init(engine); } @@ -712,6 +756,7 @@ void QQuickWidgetPrivate::handleContextCreationFailure(const QSurfaceFormat &for qFatal("%s", qPrintable(untranslatedMessage)); } +// Never called by Software Rendering backend void QQuickWidgetPrivate::createContext() { Q_Q(QQuickWidget); @@ -756,6 +801,7 @@ void QQuickWidgetPrivate::createContext() qWarning("QQuickWidget: Failed to make context current"); } +// Never called by Software Rendering backend void QQuickWidgetPrivate::destroyContext() { delete offscreenSurface; @@ -773,6 +819,13 @@ void QQuickWidget::createFramebufferObject() if (size().isEmpty()) return; + if (d->useSoftwareRenderer) { + const QSize imageSize = size() * devicePixelRatio(); + d->softwareImage = QImage(imageSize, QImage::Format_ARGB32_Premultiplied); + d->softwareImage.setDevicePixelRatio(devicePixelRatio()); + return; + } + QOpenGLContext *context = d->offscreenWindow->openglContext(); if (!context) { @@ -850,6 +903,12 @@ void QQuickWidget::createFramebufferObject() void QQuickWidget::destroyFramebufferObject() { Q_D(QQuickWidget); + + if (d->useSoftwareRenderer) { + d->softwareImage = QImage(); + return; + } + delete d->fbo; d->fbo = 0; delete d->resolvedFbo; @@ -1024,26 +1083,36 @@ void QQuickWidget::resizeEvent(QResizeEvent *e) needsSync = true; } - 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()) - return; - if (!d->fbo || d->fbo->size() != size() * devicePixelRatio()) { - needsSync = true; + // Software Renderer + if (d->useSoftwareRenderer) { + needsSync = true; + if (d->softwareImage.size() != size() * devicePixelRatio()) { createFramebufferObject(); } } else { - // This will result in a scenegraphInitialized() signal which - // is connected to createFramebufferObject(). - needsSync = true; - d->createContext(); - } - QOpenGLContext *context = d->offscreenWindow->openglContext(); - if (!context) { - qWarning("QQuickWidget::resizeEvent() no OpenGL context"); - return; + 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()) + return; + if (!d->fbo || d->fbo->size() != size() * devicePixelRatio()) { + needsSync = true; + createFramebufferObject(); + } + } else { + // This will result in a scenegraphInitialized() signal which + // is connected to createFramebufferObject(). + needsSync = true; + d->createContext(); + } + + QOpenGLContext *context = d->offscreenWindow->openglContext(); + if (!context) { + qWarning("QQuickWidget::resizeEvent() no OpenGL context"); + return; + } + } d->render(needsSync); @@ -1108,11 +1177,16 @@ void QQuickWidget::showEvent(QShowEvent *) { Q_D(QQuickWidget); d->updatePending = false; - d->createContext(); - if (d->offscreenWindow->openglContext()) - d->render(true); - else + if (!d->useSoftwareRenderer) { + d->createContext(); + if (d->offscreenWindow->openglContext()) + d->render(true); + else + triggerUpdate(); + } else { triggerUpdate(); + } + QWindowPrivate *offscreenPrivate = QWindowPrivate::get(d->offscreenWindow); if (!offscreenPrivate->visible) { offscreenPrivate->visible = true; @@ -1228,7 +1302,7 @@ bool QQuickWidget::event(QEvent *e) break; case QEvent::ScreenChangeInternal: - if (d->fbo) { + if (d->fbo || d->useSoftwareRenderer) { // This will check the size taking the devicePixelRatio into account // and recreate if needed. createFramebufferObject(); @@ -1400,3 +1474,13 @@ QQuickWindow *QQuickWidget::quickWindow() const } QT_END_NAMESPACE + + +void QQuickWidget::paintEvent(QPaintEvent *event) +{ + Q_D(QQuickWidget); + if (d->useSoftwareRenderer) { + QPainter painter(this); + painter.drawImage(rect(), d->softwareImage); + } +} diff --git a/src/quickwidgets/qquickwidget.h b/src/quickwidgets/qquickwidget.h index 0732c506bb..6e6c397c3e 100644 --- a/src/quickwidgets/qquickwidget.h +++ b/src/quickwidgets/qquickwidget.h @@ -115,34 +115,35 @@ private Q_SLOTS: void triggerUpdate(); protected: - virtual void resizeEvent(QResizeEvent *); - virtual void timerEvent(QTimerEvent*); + void resizeEvent(QResizeEvent *) override; + void timerEvent(QTimerEvent*) override; - virtual void keyPressEvent(QKeyEvent *); - virtual void keyReleaseEvent(QKeyEvent *); - virtual void mousePressEvent(QMouseEvent *); - virtual void mouseReleaseEvent(QMouseEvent *); - virtual void mouseMoveEvent(QMouseEvent *); - virtual void mouseDoubleClickEvent(QMouseEvent *); + void keyPressEvent(QKeyEvent *) override; + void keyReleaseEvent(QKeyEvent *) override; + void mousePressEvent(QMouseEvent *) override; + void mouseReleaseEvent(QMouseEvent *) override; + void mouseMoveEvent(QMouseEvent *) override; + void mouseDoubleClickEvent(QMouseEvent *) override; - virtual void showEvent(QShowEvent *); - virtual void hideEvent(QHideEvent *); + void showEvent(QShowEvent *) override; + void hideEvent(QHideEvent *) override; - virtual void focusInEvent(QFocusEvent * event); - virtual void focusOutEvent(QFocusEvent * event); + void focusInEvent(QFocusEvent * event) override; + void focusOutEvent(QFocusEvent * event) override; #ifndef QT_NO_WHEELEVENT - virtual void wheelEvent(QWheelEvent *); + void wheelEvent(QWheelEvent *) override; #endif #ifndef QT_NO_DRAGANDDROP - virtual void dragEnterEvent(QDragEnterEvent *); - virtual void dragMoveEvent(QDragMoveEvent *); - virtual void dragLeaveEvent(QDragLeaveEvent *); - virtual void dropEvent(QDropEvent *); + void dragEnterEvent(QDragEnterEvent *) override; + void dragMoveEvent(QDragMoveEvent *) override; + void dragLeaveEvent(QDragLeaveEvent *) override; + void dropEvent(QDropEvent *) override; #endif - bool event(QEvent *); + bool event(QEvent *) override; + void paintEvent(QPaintEvent *event) override; private: Q_DISABLE_COPY(QQuickWidget) diff --git a/src/quickwidgets/qquickwidget_p.h b/src/quickwidgets/qquickwidget_p.h index fd3ef8fbbf..12c6e739e1 100644 --- a/src/quickwidgets/qquickwidget_p.h +++ b/src/quickwidgets/qquickwidget_p.h @@ -134,6 +134,9 @@ public: bool fakeHidden; int requestedSamples; + + bool useSoftwareRenderer; + QImage softwareImage; }; QT_END_NAMESPACE -- cgit v1.2.3