summaryrefslogtreecommitdiffstats
path: root/src/widgets/kernel
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2017-06-07 14:35:41 +0200
committerLaszlo Agocs <laszlo.agocs@qt.io>2017-06-08 13:34:54 +0000
commit2ea90c56f2924acc5c620ed7c29a48c72a42efd3 (patch)
treee2a31ace9625ba07903d93c06ef0d0e6fe8ed0dc /src/widgets/kernel
parent41ae544c40e0568bd627a992a23b8c8f8f5cc27d (diff)
Start supporting purely offscreen QOpenGLWidget
Due to popular demand. It does have it benefits (especially when it comes to convenience) to allow grabbing QOpenGLWidgets even when they are not part of an actual window and are not actually visible. Does not involve much more than dropping the warnings and bailouts when there is active native window (because the QOpenGLWidget/its parents are still hidden). In addition the device pixel ratio from metric() has to be fixed as well. [ChangeLog][Qt Widgets] QOpenGLWidget is now able to render and return its content via grabFramebuffer(), QWidget::grab() or QWidget::render() even when the widget has not been made visible. Task-number: QTBUG-47185 Task-number: QTBUG-61280 Change-Id: Icc2b0b3ce9778a3eb6409d54744238568abb0f0d Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'src/widgets/kernel')
-rw-r--r--src/widgets/kernel/qopenglwidget.cpp32
-rw-r--r--src/widgets/kernel/qwidget.cpp5
2 files changed, 25 insertions, 12 deletions
diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp
index a852d4a474..a83884ca03 100644
--- a/src/widgets/kernel/qopenglwidget.cpp
+++ b/src/widgets/kernel/qopenglwidget.cpp
@@ -791,10 +791,8 @@ void QOpenGLWidgetPrivate::initialize()
// texture usable by the underlying window's backingstore.
QWidget *tlw = q->window();
QOpenGLContext *shareContext = get(tlw)->shareContext();
- if (Q_UNLIKELY(!shareContext)) {
- qWarning("QOpenGLWidget: Cannot be used without a context shared with the toplevel.");
- return;
- }
+ // If shareContext is null, showing content on-screen will not work.
+ // However, offscreen rendering and grabFramebuffer() will stay fully functional.
// Do not include the sample count. Requesting a multisampled context is not necessary
// since we render into an FBO, never to an actual surface. What's more, attempting to
@@ -804,9 +802,11 @@ void QOpenGLWidgetPrivate::initialize()
requestedFormat.setSamples(0);
QScopedPointer<QOpenGLContext> ctx(new QOpenGLContext);
- ctx->setShareContext(shareContext);
ctx->setFormat(requestedFormat);
- ctx->setScreen(shareContext->screen());
+ if (shareContext) {
+ ctx->setShareContext(shareContext);
+ ctx->setScreen(shareContext->screen());
+ }
if (Q_UNLIKELY(!ctx->create())) {
qWarning("QOpenGLWidget: Failed to create context");
return;
@@ -815,7 +815,9 @@ void QOpenGLWidgetPrivate::initialize()
// Propagate settings that make sense only for the tlw. Note that this only
// makes sense for properties that get picked up even after the native
// window is created.
- QSurfaceFormat tlwFormat = tlw->windowHandle()->format();
+ QSurfaceFormat tlwFormat;
+ if (tlw->windowHandle())
+ tlwFormat = tlw->windowHandle()->format();
if (requestedFormat.swapInterval() != tlwFormat.swapInterval()) {
// Most platforms will pick up the changed swap interval on the next
// makeCurrent or swapBuffers.
@@ -918,9 +920,14 @@ extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_
QImage QOpenGLWidgetPrivate::grabFramebuffer()
{
Q_Q(QOpenGLWidget);
+
+ initialize();
if (!initialized)
return QImage();
+ if (!fbo) // could be completely offscreen, without ever getting a resize event
+ recreateFbo();
+
if (!inPaintGL)
render();
@@ -1371,7 +1378,7 @@ int QOpenGLWidget::metric(QPaintDevice::PaintDeviceMetric metric) const
if (window)
return int(window->devicePixelRatio() * devicePixelRatioFScale());
else
- return 1.0;
+ return int(devicePixelRatioFScale());
default:
qWarning("QOpenGLWidget::metric(): unknown metric %d", metric);
return 0;
@@ -1422,7 +1429,14 @@ bool QOpenGLWidget::event(QEvent *e)
d->reset();
// FALLTHROUGH
case QEvent::Show: // reparenting may not lead to a resize so reinitalize on Show too
- if (!d->initialized && !size().isEmpty() && window() && window()->windowHandle()) {
+ if (d->initialized && window()->windowHandle()
+ && d->context->shareContext() != QWidgetPrivate::get(window())->shareContext())
+ {
+ // Special case: did grabFramebuffer() for a hidden widget that then became visible.
+ // Recreate all resources since the context now needs to share with the TLW's.
+ d->reset();
+ }
+ if (!d->initialized && !size().isEmpty() && window()->windowHandle()) {
d->initialize();
if (d->initialized)
d->recreateFbo();
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index 37114449ba..370ae2aed1 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -12229,10 +12229,9 @@ QOpenGLContext *QWidgetPrivate::shareContext() const
#ifdef QT_NO_OPENGL
return 0;
#else
- if (Q_UNLIKELY(!extra || !extra->topextra || !extra->topextra->window)) {
- qWarning("Asking for share context for widget that does not have a window handle");
+ if (Q_UNLIKELY(!extra || !extra->topextra || !extra->topextra->window))
return 0;
- }
+
QWidgetPrivate *that = const_cast<QWidgetPrivate *>(this);
if (!extra->topextra->shareContext) {
QOpenGLContext *ctx = new QOpenGLContext;