Fix rendercontrol grabs with the software backend

Calling grabWindow recurses (since that is implemented via
QQuickRenderControl::grab...) so it's not an option. Instead,
call directly in the software renderer implementation.

Fix also the size of the offscreen QQuickWindow when using QQuickWidget
in combination with the software backend.

Change-Id: I857a2cc0aebbbaa5d52d809aeaec37c15b0787b9
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
This commit is contained in:
Laszlo Agocs 2016-07-14 12:43:46 +02:00
parent 12de7bbc1e
commit c2414e16ab
6 changed files with 44 additions and 11 deletions

View File

@ -56,9 +56,9 @@
#include <QtQuick/QQuickWindow>
#include <QtQuick/private/qquickwindow_p.h>
#include <QtQuick/private/qsgsoftwarerenderer_p.h>
#include <QtCore/private/qobject_p.h>
QT_BEGIN_NAMESPACE
#ifndef QT_NO_OPENGL
extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
@ -369,12 +369,31 @@ QImage QQuickRenderControl::grab()
if (!d->window)
return QImage();
render();
QImage grabContent;
if (d->window->rendererInterface()->graphicsApi() == QSGRendererInterface::OpenGL) {
#ifndef QT_NO_OPENGL
QImage grabContent = qt_gl_read_framebuffer(d->window->size() * d->window->effectiveDevicePixelRatio(), false, false);
#else
QImage grabContent = d->window->grabWindow();
render();
grabContent = qt_gl_read_framebuffer(d->window->size() * d->window->effectiveDevicePixelRatio(), false, false);
#endif
} else if (d->window->rendererInterface()->graphicsApi() == QSGRendererInterface::Software) {
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(d->window);
QSGSoftwareRenderer *softwareRenderer = static_cast<QSGSoftwareRenderer *>(cd->renderer);
if (softwareRenderer) {
const qreal dpr = d->window->effectiveDevicePixelRatio();
const QSize imageSize = d->window->size() * dpr;
grabContent = QImage(imageSize, QImage::Format_ARGB32_Premultiplied);
grabContent.setDevicePixelRatio(dpr);
QPaintDevice *prevDev = softwareRenderer->currentPaintDevice();
softwareRenderer->setCurrentPaintDevice(&grabContent);
softwareRenderer->markDirty();
render();
softwareRenderer->setCurrentPaintDevice(prevDev);
}
} else {
qWarning("QQuickRenderControl: grabs are not supported with the current Qt Quick backend");
}
return grabContent;
}

View File

@ -236,7 +236,7 @@ void QSGAbstractSoftwareRenderer::setBackgroundSize(const QSize &size)
m_background->setRect(0.0f, 0.0f, size.width(), size.height());
renderableNode(m_background)->markGeometryDirty();
// Invalidate the whole scene when the background is resized
m_dirtyRegion = QRegion(m_background->rect().toRect());
markDirty();
}
QColor QSGAbstractSoftwareRenderer::backgroundColor()
@ -322,4 +322,9 @@ void QSGAbstractSoftwareRenderer::nodeOpacityUpdated(QSGNode *node)
m_nodeUpdater->updateNodes(node);
}
void QSGAbstractSoftwareRenderer::markDirty()
{
m_dirtyRegion = QRegion(m_background->rect().toRect());
}
QT_END_NAMESPACE

View File

@ -75,6 +75,8 @@ public:
void nodeChanged(QSGNode *node, QSGNode::DirtyState state) override;
void markDirty();
protected:
QRegion renderNodes(QPainter *painter);
void buildRenderList();

View File

@ -69,6 +69,11 @@ void QSGSoftwareRenderer::setCurrentPaintDevice(QPaintDevice *device)
m_backingStore = nullptr;
}
QPaintDevice *QSGSoftwareRenderer::currentPaintDevice() const
{
return m_paintDevice;
}
void QSGSoftwareRenderer::setBackingStore(QBackingStore *backingStore)
{
m_backingStore = backingStore;

View File

@ -65,6 +65,7 @@ public:
virtual ~QSGSoftwareRenderer();
void setCurrentPaintDevice(QPaintDevice *device);
QPaintDevice *currentPaintDevice() const;
void setBackingStore(QBackingStore *backingStore);
QRegion flushRegion() const;

View File

@ -894,6 +894,12 @@ void QQuickWidget::createFramebufferObject()
if (size().isEmpty())
return;
// Even though this is just an offscreen window we should set the position on it, as it might be
// useful for an item to know the actual position of the scene.
// Note: The position will be update when we get a move event (see: updatePosition()).
const QPoint &globalPos = mapToGlobal(QPoint(0, 0));
d->offscreenWindow->setGeometry(globalPos.x(), globalPos.y(), width(), height());
if (d->useSoftwareRenderer) {
const QSize imageSize = size() * devicePixelRatio();
d->softwareImage = QImage(imageSize, QImage::Format_ARGB32_Premultiplied);
@ -961,11 +967,6 @@ void QQuickWidget::createFramebufferObject()
}
#endif
// Even though this is just an offscreen window we should set the position on it, as it might be
// useful for an item to know the actual position of the scene.
// Note: The position will be update when we get a move event (see: updatePosition()).
const QPoint &globalPos = mapToGlobal(QPoint(0, 0));
d->offscreenWindow->setGeometry(globalPos.x(), globalPos.y(), width(), height());
d->offscreenWindow->setRenderTarget(d->fbo);
if (samples > 0)