diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2017-06-07 14:35:41 +0200 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2017-06-08 13:34:54 +0000 |
commit | 2ea90c56f2924acc5c620ed7c29a48c72a42efd3 (patch) | |
tree | e2a31ace9625ba07903d93c06ef0d0e6fe8ed0dc /src/widgets/kernel | |
parent | 41ae544c40e0568bd627a992a23b8c8f8f5cc27d (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.cpp | 32 | ||||
-rw-r--r-- | src/widgets/kernel/qwidget.cpp | 5 |
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; |