aboutsummaryrefslogtreecommitdiffstats
path: root/src/quickwidgets
diff options
context:
space:
mode:
Diffstat (limited to 'src/quickwidgets')
-rw-r--r--src/quickwidgets/qquickwidget.cpp247
-rw-r--r--src/quickwidgets/qquickwidget.h39
-rw-r--r--src/quickwidgets/qquickwidget_p.h4
3 files changed, 198 insertions, 92 deletions
diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp
index 2839607bae..26a540455e 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 <private/qqmldebugconnector_p.h>
#include <private/qquickprofiler_p.h>
#include <private/qqmldebugserviceinterfaces_p.h>
@@ -57,6 +59,13 @@
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/qpa/qplatformintegration.h>
+#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLFunctions>
+#include <QtGui/private/qopenglextensions_p.h>
+#include <QtGui/QPainter>
+
+#include <QtQuick/QSGRendererInterface>
+
#ifdef Q_OS_WIN
# include <QtWidgets/QMessageBox>
# include <QtCore/QLibraryInfo>
@@ -89,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;
@@ -114,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();
@@ -129,7 +147,8 @@ void QQuickWidgetPrivate::invalidateRenderControl()
void QQuickWidgetPrivate::handleWindowChange()
{
invalidateRenderControl();
- destroyContext();
+ if (!useSoftwareRenderer)
+ destroyContext();
}
QQuickWidgetPrivate::QQuickWidgetPrivate()
@@ -147,6 +166,7 @@ QQuickWidgetPrivate::QQuickWidgetPrivate()
, updatePending(false)
, fakeHidden(false)
, requestedSamples(0)
+ , useSoftwareRenderer(false)
{
}
@@ -154,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()
@@ -204,35 +229,52 @@ void QQuickWidgetPrivate::itemGeometryChanged(QQuickItem *resizeItem, const QRec
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<QOpenGLExtensions *>(context->functions())->flushShared();
+
+ QOpenGLContextPrivate::get(context)->defaultFboRedirect = 0;
+ } else {
+ //Software Renderer
+ if (needsSync) {
+ renderControl->polishItems();
+ renderControl->sync();
+ }
- static_cast<QOpenGLExtensions *>(context->functions())->flushShared();
+ QQuickWindowPrivate *cd = QQuickWindowPrivate::get(offscreenWindow);
+ auto softwareRenderer = static_cast<QSGSoftwareRenderer*>(cd->renderer);
+ if (softwareRenderer) {
+ softwareRenderer->setCurrentPaintDevice(&softwareImage);
+ renderControl->render();
- QOpenGLContextPrivate::get(context)->defaultFboRedirect = 0;
+ updateRegion += softwareRenderer->flushRegion();
+ }
+ }
}
void QQuickWidgetPrivate::renderSceneGraph()
@@ -243,13 +285,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);
@@ -258,15 +302,22 @@ void QQuickWidgetPrivate::renderSceneGraph()
QWidgetPrivate::nearestGraphicsProxyWidget(q)->update();
else
#endif
- q->update(); // schedule composition
+ {
+ if (!useSoftwareRenderer)
+ q->update(); // schedule composition
+ else if (!updateRegion.isEmpty())
+ q->update(updateRegion);
+ }
}
QImage QQuickWidgetPrivate::grabFramebuffer()
{
- if (!context)
- return QImage();
+ if (!useSoftwareRenderer) {
+ if (!context)
+ return QImage();
- context->makeCurrent(offscreenSurface);
+ context->makeCurrent(offscreenSurface);
+ }
return renderControl->grab();
}
@@ -705,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);
@@ -749,6 +801,7 @@ void QQuickWidgetPrivate::createContext()
qWarning("QQuickWidget: Failed to make context current");
}
+// Never called by Software Rendering backend
void QQuickWidgetPrivate::destroyContext()
{
delete offscreenSurface;
@@ -766,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) {
@@ -843,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;
@@ -1017,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);
@@ -1100,12 +1176,16 @@ void QQuickWidget::mouseDoubleClickEvent(QMouseEvent *e)
void QQuickWidget::showEvent(QShowEvent *)
{
Q_D(QQuickWidget);
- d->createContext();
- if (d->offscreenWindow->openglContext()) {
- d->render(true);
- if (d->updatePending) {
- d->updatePending = false;
- update();
+ if (!d->useSoftwareRenderer) {
+ d->createContext();
+ if (d->offscreenWindow->openglContext()) {
+ d->render(true);
+ if (d->updatePending) {
+ d->updatePending = false;
+ update();
+ }
+ } else {
+ triggerUpdate();
}
} else {
triggerUpdate();
@@ -1225,7 +1305,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();
@@ -1397,3 +1477,24 @@ QQuickWindow *QQuickWidget::quickWindow() const
}
QT_END_NAMESPACE
+
+
+void QQuickWidget::paintEvent(QPaintEvent *event)
+{
+ Q_UNUSED(event)
+ Q_D(QQuickWidget);
+ if (d->useSoftwareRenderer) {
+ QPainter painter(this);
+ if (d->updateRegion.isNull()) {
+ //Paint everything
+ painter.drawImage(rect(), d->softwareImage);
+ } else {
+ //Paint only the updated areas
+ for (auto targetRect : d->updateRegion.rects()) {
+ auto sourceRect = QRect(targetRect.topLeft() * devicePixelRatio(), targetRect.size() * devicePixelRatio());
+ painter.drawImage(targetRect, d->softwareImage, sourceRect);
+ }
+ d->updateRegion = QRegion();
+ }
+ }
+}
diff --git a/src/quickwidgets/qquickwidget.h b/src/quickwidgets/qquickwidget.h
index 0732c506bb..56e6b01ac5 100644
--- a/src/quickwidgets/qquickwidget.h
+++ b/src/quickwidgets/qquickwidget.h
@@ -87,7 +87,7 @@ public:
QList<QQmlError> errors() const;
- QSize sizeHint() const;
+ QSize sizeHint() const override;
QSize initialSize() const;
void setFormat(const QSurfaceFormat &format);
@@ -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..5c35093c58 100644
--- a/src/quickwidgets/qquickwidget_p.h
+++ b/src/quickwidgets/qquickwidget_p.h
@@ -134,6 +134,10 @@ public:
bool fakeHidden;
int requestedSamples;
+
+ bool useSoftwareRenderer;
+ QImage softwareImage;
+ QRegion updateRegion;
};
QT_END_NAMESPACE