diff options
Diffstat (limited to 'src/widgets/kernel/qopenglwidget.cpp')
| -rw-r--r-- | src/widgets/kernel/qopenglwidget.cpp | 63 |
1 files changed, 41 insertions, 22 deletions
diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp index 1ee28f2e9a0..92f60669369 100644 --- a/src/widgets/kernel/qopenglwidget.cpp +++ b/src/widgets/kernel/qopenglwidget.cpp @@ -425,7 +425,12 @@ QT_BEGIN_NAMESPACE Note that this does not apply when there are no other widgets underneath and the intention is to have a semi-transparent window. In that case the - traditional approach of setting Qt::WA_TranslucentBackground is sufficient. + traditional approach of setting Qt::WA_TranslucentBackground + on the top-level window is sufficient. Note that if the transparent areas are + only desired in the QOpenGLWidget, then Qt::WA_NoSystemBackground will need + to be turned back to \c false after enabling Qt::WA_TranslucentBackground. + Additionally, requesting an alpha channel for the QOpenGLWidget's context via + setFormat() may be necessary too, depending on the system. QOpenGLWidget supports multiple update behaviors, just like QOpenGLWindow. In preserved mode the rendered content from the previous paintGL() call is @@ -553,7 +558,8 @@ public: hasBeenComposed(false), flushPending(false), paintDevice(0), - updateBehavior(QOpenGLWidget::NoPartialUpdate) + updateBehavior(QOpenGLWidget::NoPartialUpdate), + requestedSamples(0) { requestedFormat = QSurfaceFormat::defaultFormat(); } @@ -595,6 +601,7 @@ public: QOpenGLPaintDevice *paintDevice; QSurfaceFormat requestedFormat; QOpenGLWidget::UpdateBehavior updateBehavior; + int requestedSamples; }; void QOpenGLWidgetPaintDevicePrivate::beginPaint() @@ -605,7 +612,7 @@ void QOpenGLWidgetPaintDevicePrivate::beginPaint() // with the palette's background color. if (w->autoFillBackground()) { QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); - if (w->testAttribute(Qt::WA_TranslucentBackground)) { + if (w->format().hasAlpha()) { f->glClearColor(0, 0, 0, 0); } else { QColor c = w->palette().brush(w->backgroundRole()).color(); @@ -686,7 +693,7 @@ void QOpenGLWidgetPrivate::recreateFbo() delete resolvedFbo; resolvedFbo = 0; - int samples = context->format().samples(); + int samples = requestedSamples; QOpenGLExtensions *extfuncs = static_cast<QOpenGLExtensions *>(context->functions()); if (!extfuncs->hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) samples = 0; @@ -695,7 +702,7 @@ void QOpenGLWidgetPrivate::recreateFbo() format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); format.setSamples(samples); - const QSize deviceSize = q->size() * q->devicePixelRatio(); + const QSize deviceSize = q->size() * q->devicePixelRatioF(); fbo = new QOpenGLFramebufferObject(deviceSize, format); if (samples > 0) resolvedFbo = new QOpenGLFramebufferObject(deviceSize); @@ -704,7 +711,7 @@ void QOpenGLWidgetPrivate::recreateFbo() context->functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); paintDevice->setSize(deviceSize); - paintDevice->setDevicePixelRatio(q->devicePixelRatio()); + paintDevice->setDevicePixelRatio(q->devicePixelRatioF()); emit q->resized(); } @@ -742,6 +749,13 @@ void QOpenGLWidgetPrivate::initialize() return; } + // 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 + // create a pbuffer with a multisampled config crashes certain implementations. Just + // avoid the entire hassle, the result is the same. + requestedSamples = requestedFormat.samples(); + requestedFormat.setSamples(0); + QScopedPointer<QOpenGLContext> ctx(new QOpenGLContext); ctx->setShareContext(shareContext); ctx->setFormat(requestedFormat); @@ -778,8 +792,8 @@ void QOpenGLWidgetPrivate::initialize() } paintDevice = new QOpenGLWidgetPaintDevice(q); - paintDevice->setSize(q->size() * q->devicePixelRatio()); - paintDevice->setDevicePixelRatio(q->devicePixelRatio()); + paintDevice->setSize(q->size() * q->devicePixelRatioF()); + paintDevice->setDevicePixelRatio(q->devicePixelRatioF()); context = ctx.take(); initialized = true; @@ -808,7 +822,7 @@ void QOpenGLWidgetPrivate::invokeUserPaint() QOpenGLFunctions *f = ctx->functions(); QOpenGLContextPrivate::get(ctx)->defaultFboRedirect = fbo->handle(); - f->glViewport(0, 0, q->width() * q->devicePixelRatio(), q->height() * q->devicePixelRatio()); + f->glViewport(0, 0, q->width() * q->devicePixelRatioF(), q->height() * q->devicePixelRatioF()); q->paintGL(); flushPending = true; @@ -859,8 +873,8 @@ QImage QOpenGLWidgetPrivate::grabFramebuffer() render(); resolveSamples(); q->makeCurrent(); - QImage res = qt_gl_read_framebuffer(q->size() * q->devicePixelRatio(), false, false); - res.setDevicePixelRatio(q->devicePixelRatio()); + QImage res = qt_gl_read_framebuffer(q->size() * q->devicePixelRatioF(), false, false); + res.setDevicePixelRatio(q->devicePixelRatioF()); return res; } @@ -879,7 +893,7 @@ void QOpenGLWidgetPrivate::resizeViewportFramebuffer() if (!initialized) return; - if (!fbo || q->size() * q->devicePixelRatio() != fbo->size()) + if (!fbo || q->size() * q->devicePixelRatioF() != fbo->size()) recreateFbo(); } @@ -946,13 +960,12 @@ QOpenGLWidget::UpdateBehavior QOpenGLWidget::updateBehavior() const OpenGL widgets, individual calls to this function can be replaced by one single call to QSurfaceFormat::setDefaultFormat() before creating the first widget. - \note Requesting an alpha buffer via this function, or by setting - Qt::WA_TranslucentBackground, will not lead to the desired results when the intention is - to make other widgets beneath visible. Instead, use Qt::WA_AlwaysStackOnTop to enable - semi-transparent QOpenGLWidget instances with other widgets visible underneath. Keep in - mind however that this breaks the stacking order, so it will no longer be possible to - have other widgets on top of the QOpenGLWidget. When the intention is to have a - semi-transparent top-level window, Qt::WA_TranslucentBackground is sufficient. + \note Requesting an alpha buffer via this function will not lead to the + desired results when the intention is to make other widgets beneath visible. + Instead, use Qt::WA_AlwaysStackOnTop to enable semi-transparent QOpenGLWidget + instances with other widgets visible underneath. Keep in mind however that + this breaks the stacking order, so it will no longer be possible to have + other widgets on top of the QOpenGLWidget. \sa format(), Qt::WA_AlwaysStackOnTop, QSurfaceFormat::setDefaultFormat() */ @@ -1196,6 +1209,7 @@ int QOpenGLWidget::metric(QPaintDevice::PaintDeviceMetric metric) const return QWidget::metric(metric); QWidget *tlw = window(); + QWindow *window = tlw ? tlw->windowHandle() : 0; QScreen *screen = tlw && tlw->windowHandle() ? tlw->windowHandle()->screen() : 0; if (!screen && QGuiApplication::primaryScreen()) screen = QGuiApplication::primaryScreen(); @@ -1243,8 +1257,13 @@ int QOpenGLWidget::metric(QPaintDevice::PaintDeviceMetric metric) const else return qRound(dpmy * 0.0254); case PdmDevicePixelRatio: - if (screen) - return screen->devicePixelRatio(); + if (window) + return int(window->devicePixelRatio()); + else + return 1.0; + case PdmDevicePixelRatioScaled: + if (window) + return int(window->devicePixelRatio() * devicePixelRatioFScale()); else return 1.0; default: @@ -1304,7 +1323,7 @@ bool QOpenGLWidget::event(QEvent *e) } break; case QEvent::ScreenChangeInternal: - if (d->initialized && d->paintDevice->devicePixelRatio() != devicePixelRatio()) + if (d->initialized && d->paintDevice->devicePixelRatioF() != devicePixelRatioF()) d->recreateFbo(); break; default: |
