summaryrefslogtreecommitdiffstats
path: root/src/widgets/kernel/qopenglwidget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/kernel/qopenglwidget.cpp')
-rw-r--r--src/widgets/kernel/qopenglwidget.cpp134
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();