diff options
Diffstat (limited to 'src/widgets/kernel/qopenglwidget.cpp')
-rw-r--r-- | src/widgets/kernel/qopenglwidget.cpp | 134 |
1 files changed, 113 insertions, 21 deletions
diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp index 218d3c4a46..5bc408a8cd 100644 --- a/src/widgets/kernel/qopenglwidget.cpp +++ b/src/widgets/kernel/qopenglwidget.cpp @@ -567,7 +567,8 @@ public: paintDevice(0), updateBehavior(QOpenGLWidget::NoPartialUpdate), requestedSamples(0), - inPaintGL(false) + inPaintGL(false), + textureFormat(0) { requestedFormat = QSurfaceFormat::defaultFormat(); } @@ -576,6 +577,7 @@ public: void recreateFbo(); GLuint textureId() const Q_DECL_OVERRIDE; + QPlatformTextureList::Flags textureListFlags() Q_DECL_OVERRIDE; void initialize(); void invokeUserPaint(); @@ -606,6 +608,7 @@ public: QOpenGLWidget::UpdateBehavior updateBehavior; int requestedSamples; bool inPaintGL; + GLenum textureFormat; }; void QOpenGLWidgetPaintDevicePrivate::beginPaint() @@ -663,6 +666,35 @@ GLuint QOpenGLWidgetPrivate::textureId() const return resolvedFbo ? resolvedFbo->texture() : (fbo ? fbo->texture() : 0); } +#ifndef GL_SRGB +#define GL_SRGB 0x8C40 +#endif +#ifndef GL_SRGB8 +#define GL_SRGB8 0x8C41 +#endif +#ifndef GL_SRGB_ALPHA +#define GL_SRGB_ALPHA 0x8C42 +#endif +#ifndef GL_SRGB8_ALPHA8 +#define GL_SRGB8_ALPHA8 0x8C43 +#endif + +QPlatformTextureList::Flags QOpenGLWidgetPrivate::textureListFlags() +{ + QPlatformTextureList::Flags flags = QWidgetPrivate::textureListFlags(); + switch (textureFormat) { + case GL_SRGB: + case GL_SRGB8: + case GL_SRGB_ALPHA: + case GL_SRGB8_ALPHA8: + flags |= QPlatformTextureList::TextureIsSrgb; + break; + default: + break; + } + return flags; +} + void QOpenGLWidgetPrivate::reset() { Q_Q(QOpenGLWidget); @@ -712,12 +744,16 @@ void QOpenGLWidgetPrivate::recreateFbo() QOpenGLFramebufferObjectFormat format; format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); format.setSamples(samples); + if (textureFormat) + format.setInternalTextureFormat(textureFormat); const QSize deviceSize = q->size() * q->devicePixelRatioF(); fbo = new QOpenGLFramebufferObject(deviceSize, format); if (samples > 0) resolvedFbo = new QOpenGLFramebufferObject(deviceSize); + textureFormat = fbo->format().internalTextureFormat(); + fbo->bind(); context->functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); @@ -755,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 @@ -768,25 +802,31 @@ 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; } - // Propagate settings that make sense only for the tlw. - QSurfaceFormat tlwFormat = tlw->windowHandle()->format(); - if (requestedFormat.swapInterval() != tlwFormat.swapInterval()) { - // Most platforms will pick up the changed swap interval on the next - // makeCurrent or swapBuffers. - tlwFormat.setSwapInterval(requestedFormat.swapInterval()); - tlw->windowHandle()->setFormat(tlwFormat); - } - if (requestedFormat.swapBehavior() != tlwFormat.swapBehavior()) { - tlwFormat.setSwapBehavior(requestedFormat.swapBehavior()); - tlw->windowHandle()->setFormat(tlwFormat); + // 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. + if (tlw->windowHandle()) { + QSurfaceFormat tlwFormat = tlw->windowHandle()->format(); + if (requestedFormat.swapInterval() != tlwFormat.swapInterval()) { + // Most platforms will pick up the changed swap interval on the next + // makeCurrent or swapBuffers. + tlwFormat.setSwapInterval(requestedFormat.swapInterval()); + tlw->windowHandle()->setFormat(tlwFormat); + } + if (requestedFormat.swapBehavior() != tlwFormat.swapBehavior()) { + tlwFormat.setSwapBehavior(requestedFormat.swapBehavior()); + tlw->windowHandle()->setFormat(tlwFormat); + } } // The top-level window's surface is not good enough since it causes way too @@ -880,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(); @@ -1000,7 +1045,6 @@ QOpenGLWidget::UpdateBehavior QOpenGLWidget::updateBehavior() const */ void QOpenGLWidget::setFormat(const QSurfaceFormat &format) { - Q_UNUSED(format); Q_D(QOpenGLWidget); if (Q_UNLIKELY(d->initialized)) { qWarning("QOpenGLWidget: Already initialized, setting the format has no effect"); @@ -1033,6 +1077,47 @@ QSurfaceFormat QOpenGLWidget::format() const } /*! + Sets a custom internal texture format of \a texFormat. + + When working with sRGB framebuffers, it will be necessary to specify a + format like \c{GL_SRGB8_ALPHA8}. This can be achieved by calling this + function. + + \note This function has no effect if called after the widget has already + been shown and thus it performed initialization. + + \note This function will typically have to be used in combination with a + QSurfaceFormat::setDefaultFormat() call that sets the color space to + QSurfaceFormat::sRGBColorSpace. + + \since 5.10 + */ +void QOpenGLWidget::setTextureFormat(GLenum texFormat) +{ + Q_D(QOpenGLWidget); + if (Q_UNLIKELY(d->initialized)) { + qWarning("QOpenGLWidget: Already initialized, setting the internal texture format has no effect"); + return; + } + + d->textureFormat = texFormat; +} + +/*! + \return the active internal texture format if the widget has already + initialized, the requested format if one was set but the widget has not yet + been made visible, or 0 if setTextureFormat() was not called and the widget + has not yet been made visible. + + \since 5.10 + */ +GLenum QOpenGLWidget::textureFormat() const +{ + Q_D(const QOpenGLWidget); + return d->textureFormat; +} + +/*! \return \e true if the widget and OpenGL resources, like the context, have been successfully initialized. Note that the return value is always false until the widget is shown. @@ -1293,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; @@ -1346,7 +1431,14 @@ bool QOpenGLWidget::event(QEvent *e) break; // 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(); |