From 931e4ae66504f5d0be9d097565b4e9f49a92c69a Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 20 Feb 2017 14:48:56 +0100 Subject: Support windows with sRGB-capable default framebuffers in QSurfaceFormat Backend implementation is done for GLX for now. WGL and EGL may follow later on. [ChangeLog][QtGui] Added support for requesting OpenGL windows with sRGB-capable default framebuffers. While this is implicit on some platforms, QSurfaceFormat now has the necessary flags to request such windows in a cross-platform manner. Task-number: QTBUG-50987 Change-Id: I4df1f786e41e63396f46920a81afdf5ecb5eedea Reviewed-by: Andy Nichols --- src/gui/kernel/qsurfaceformat.cpp | 69 +++++++++++++++++++++- src/gui/kernel/qsurfaceformat.h | 9 +++ .../glxconvenience/qglxconvenience.cpp | 48 +++++++++++---- .../glxconvenience/qglxconvenience_p.h | 15 +++-- .../xcb/gl_integrations/xcb_glx/qxcbglxwindow.cpp | 17 +++++- 5 files changed, 141 insertions(+), 17 deletions(-) diff --git a/src/gui/kernel/qsurfaceformat.cpp b/src/gui/kernel/qsurfaceformat.cpp index 000d727380..574310f554 100644 --- a/src/gui/kernel/qsurfaceformat.cpp +++ b/src/gui/kernel/qsurfaceformat.cpp @@ -73,6 +73,7 @@ public: , major(2) , minor(0) , swapInterval(1) // default to vsync + , colorSpace(QSurfaceFormat::DefaultColorSpace) { } @@ -91,7 +92,8 @@ public: profile(other->profile), major(other->major), minor(other->minor), - swapInterval(other->swapInterval) + swapInterval(other->swapInterval), + colorSpace(other->colorSpace) { } @@ -110,6 +112,7 @@ public: int major; int minor; int swapInterval; + QSurfaceFormat::ColorSpace colorSpace; }; /*! @@ -124,6 +127,12 @@ public: contains surface configuration parameters such as OpenGL profile and version for rendering, whether or not to enable stereo buffers, and swap behaviour. + + \note When troubleshooting context or window format issues, it can be + helpful to enable the logging category \c{qt.qpa.gl}. Depending on the + platform, this may print useful debug information when it comes to OpenGL + initialization and the native visual or framebuffer configurations which + QSurfaceFormat gets mapped to. */ /*! @@ -198,6 +207,22 @@ public: \value CompatibilityProfile Functionality from earlier OpenGL versions is available. */ +/*! + \enum QSurfaceFormat::ColorSpace + + This enum is used to specify the preferred color space, controlling if the + window's associated default framebuffer is able to do updates and blending + in a given encoding instead of the standard linear operations. + + \value DefaultColorSpace The default, unspecified color space. + + \value sRGBColorSpace When \c{GL_ARB_framebuffer_sRGB} or + \c{GL_EXT_framebuffer_sRGB} is supported by the platform and this value is + set, the window will be created with an sRGB-capable default + framebuffer. Note that some platforms may return windows with a sRGB-capable + default framebuffer even when not requested explicitly. + */ + /*! Constructs a default initialized QSurfaceFormat. @@ -736,6 +761,47 @@ int QSurfaceFormat::swapInterval() const return d->swapInterval; } +/*! + Sets the preferred \a colorSpace. + + For example, this allows requesting windows with default framebuffers that + are sRGB-capable on platforms that support it. + + \note When the requested color space is not supported by the platform, the + request is ignored. Query the QSurfaceFormat after window creation to verify + if the color space request could be honored or not. + + \note This setting controls if the default framebuffer of the window is + capable of updates and blending in a given color space. It does not change + applications' output by itself. The applications' rendering code will still + have to opt in via the appropriate OpenGL calls to enable updates and + blending to be performed in the given color space instead of using the + standard linear operations. + + \since 5.10 + + \sa colorSpace() + */ +void QSurfaceFormat::setColorSpace(ColorSpace colorSpace) +{ + if (d->colorSpace != colorSpace) { + detach(); + d->colorSpace = colorSpace; + } +} + +/*! + \return the color space. + + \since 5.10 + + \sa setColorSpace() +*/ +QSurfaceFormat::ColorSpace QSurfaceFormat::colorSpace() const +{ + return d->colorSpace; +} + Q_GLOBAL_STATIC(QSurfaceFormat, qt_default_surface_format) /*! @@ -841,6 +907,7 @@ QDebug operator<<(QDebug dbg, const QSurfaceFormat &f) << ", samples " << d->numSamples << ", swapBehavior " << d->swapBehavior << ", swapInterval " << d->swapInterval + << ", colorSpace " << d->colorSpace << ", profile " << d->profile << ')'; diff --git a/src/gui/kernel/qsurfaceformat.h b/src/gui/kernel/qsurfaceformat.h index 246163609e..ed63eb8bbf 100644 --- a/src/gui/kernel/qsurfaceformat.h +++ b/src/gui/kernel/qsurfaceformat.h @@ -85,6 +85,12 @@ public: }; Q_ENUM(OpenGLContextProfile) + enum ColorSpace { + DefaultColorSpace, + sRGBColorSpace + }; + Q_ENUM(ColorSpace) + QSurfaceFormat(); /*implicit*/ QSurfaceFormat(FormatOptions options); QSurfaceFormat(const QSurfaceFormat &other); @@ -145,6 +151,9 @@ public: int swapInterval() const; void setSwapInterval(int interval); + ColorSpace colorSpace() const; + void setColorSpace(ColorSpace colorSpace); + static void setDefaultFormat(const QSurfaceFormat &format); static QSurfaceFormat defaultFormat(); diff --git a/src/platformsupport/glxconvenience/qglxconvenience.cpp b/src/platformsupport/glxconvenience/qglxconvenience.cpp index 4225bebf37..c7b5470b39 100644 --- a/src/platformsupport/glxconvenience/qglxconvenience.cpp +++ b/src/platformsupport/glxconvenience/qglxconvenience.cpp @@ -76,7 +76,11 @@ enum { #undef FontChange #endif -QVector qglx_buildSpec(const QSurfaceFormat &format, int drawableBit) +#ifndef GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB +#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2 +#endif + +QVector qglx_buildSpec(const QSurfaceFormat &format, int drawableBit, int flags) { QVector spec; @@ -120,6 +124,10 @@ QVector qglx_buildSpec(const QSurfaceFormat &format, int drawableBit) << GLX_SAMPLES_ARB << format.samples(); + if ((flags & QGLX_SUPPORTS_SRGB) && format.colorSpace() == QSurfaceFormat::sRGBColorSpace) + spec << GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB + << True; + spec << GLX_DRAWABLE_TYPE << drawableBit @@ -179,14 +187,14 @@ template using QXlibArrayPointer = QScopedArrayPointer>; } -GLXFBConfig qglx_findConfig(Display *display, int screen , QSurfaceFormat format, bool highestPixelFormat, int drawableBit) +GLXFBConfig qglx_findConfig(Display *display, int screen , QSurfaceFormat format, bool highestPixelFormat, int drawableBit, int flags) { QXcbSoftwareOpenGLEnforcer softwareOpenGLEnforcer; GLXFBConfig config = 0; do { - const QVector spec = qglx_buildSpec(format, drawableBit); + const QVector spec = qglx_buildSpec(format, drawableBit, flags); int confcount = 0; QXlibArrayPointer configs(glXChooseFBConfig(display, screen, spec.constData(), &confcount)); @@ -205,6 +213,13 @@ GLXFBConfig qglx_findConfig(Display *display, int screen , QSurfaceFormat format for (int i = 0; i < confcount; i++) { GLXFBConfig candidate = configs[i]; + if ((flags & QGLX_SUPPORTS_SRGB) && format.colorSpace() == QSurfaceFormat::sRGBColorSpace) { + int srgbCapable = 0; + glXGetFBConfigAttrib(display, candidate, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, &srgbCapable); + if (!srgbCapable) + continue; + } + QXlibPointer visual(glXGetVisualFromFBConfig(display, candidate)); const int actualRed = qPopulationCount(visual->red_mask); @@ -228,28 +243,28 @@ GLXFBConfig qglx_findConfig(Display *display, int screen , QSurfaceFormat format return config; } -XVisualInfo *qglx_findVisualInfo(Display *display, int screen, QSurfaceFormat *format, int drawableBit) +XVisualInfo *qglx_findVisualInfo(Display *display, int screen, QSurfaceFormat *format, int drawableBit, int flags) { Q_ASSERT(format); XVisualInfo *visualInfo = 0; - GLXFBConfig config = qglx_findConfig(display, screen, *format, false, drawableBit); + GLXFBConfig config = qglx_findConfig(display, screen, *format, false, drawableBit, flags); if (config) visualInfo = glXGetVisualFromFBConfig(display, config); if (visualInfo) { - qglx_surfaceFormatFromGLXFBConfig(format, display, config); + qglx_surfaceFormatFromGLXFBConfig(format, display, config, flags); return visualInfo; } // attempt to fall back to glXChooseVisual do { - QVector attribs = qglx_buildSpec(*format, drawableBit); + QVector attribs = qglx_buildSpec(*format, drawableBit, flags); visualInfo = glXChooseVisual(display, screen, attribs.data()); if (visualInfo) { - qglx_surfaceFormatFromVisualInfo(format, display, visualInfo); + qglx_surfaceFormatFromVisualInfo(format, display, visualInfo, flags); return visualInfo; } } while (qglx_reduceFormat(format)); @@ -257,7 +272,7 @@ XVisualInfo *qglx_findVisualInfo(Display *display, int screen, QSurfaceFormat *f return visualInfo; } -void qglx_surfaceFormatFromGLXFBConfig(QSurfaceFormat *format, Display *display, GLXFBConfig config) +void qglx_surfaceFormatFromGLXFBConfig(QSurfaceFormat *format, Display *display, GLXFBConfig config, int flags) { int redSize = 0; int greenSize = 0; @@ -268,6 +283,7 @@ void qglx_surfaceFormatFromGLXFBConfig(QSurfaceFormat *format, Display *display, int sampleBuffers = 0; int sampleCount = 0; int stereo = 0; + int srgbCapable = 0; glXGetFBConfigAttrib(display, config, GLX_RED_SIZE, &redSize); glXGetFBConfigAttrib(display, config, GLX_GREEN_SIZE, &greenSize); @@ -277,6 +293,8 @@ void qglx_surfaceFormatFromGLXFBConfig(QSurfaceFormat *format, Display *display, glXGetFBConfigAttrib(display, config, GLX_STENCIL_SIZE, &stencilSize); glXGetFBConfigAttrib(display, config, GLX_SAMPLES_ARB, &sampleBuffers); glXGetFBConfigAttrib(display, config, GLX_STEREO, &stereo); + if (flags & QGLX_SUPPORTS_SRGB) + glXGetFBConfigAttrib(display, config, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, &srgbCapable); format->setRedBufferSize(redSize); format->setGreenBufferSize(greenSize); @@ -288,11 +306,12 @@ void qglx_surfaceFormatFromGLXFBConfig(QSurfaceFormat *format, Display *display, glXGetFBConfigAttrib(display, config, GLX_SAMPLES_ARB, &sampleCount); format->setSamples(sampleCount); } + format->setColorSpace(srgbCapable ? QSurfaceFormat::sRGBColorSpace : QSurfaceFormat::DefaultColorSpace); format->setStereo(stereo); } -void qglx_surfaceFormatFromVisualInfo(QSurfaceFormat *format, Display *display, XVisualInfo *visualInfo) +void qglx_surfaceFormatFromVisualInfo(QSurfaceFormat *format, Display *display, XVisualInfo *visualInfo, int flags) { int redSize = 0; int greenSize = 0; @@ -303,6 +322,7 @@ void qglx_surfaceFormatFromVisualInfo(QSurfaceFormat *format, Display *display, int sampleBuffers = 0; int sampleCount = 0; int stereo = 0; + int srgbCapable = 0; glXGetConfig(display, visualInfo, GLX_RED_SIZE, &redSize); glXGetConfig(display, visualInfo, GLX_GREEN_SIZE, &greenSize); @@ -312,6 +332,8 @@ void qglx_surfaceFormatFromVisualInfo(QSurfaceFormat *format, Display *display, glXGetConfig(display, visualInfo, GLX_STENCIL_SIZE, &stencilSize); glXGetConfig(display, visualInfo, GLX_SAMPLES_ARB, &sampleBuffers); glXGetConfig(display, visualInfo, GLX_STEREO, &stereo); + if (flags & QGLX_SUPPORTS_SRGB) + glXGetConfig(display, visualInfo, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, &srgbCapable); format->setRedBufferSize(redSize); format->setGreenBufferSize(greenSize); @@ -323,6 +345,7 @@ void qglx_surfaceFormatFromVisualInfo(QSurfaceFormat *format, Display *display, glXGetConfig(display, visualInfo, GLX_SAMPLES_ARB, &sampleCount); format->setSamples(sampleCount); } + format->setColorSpace(srgbCapable ? QSurfaceFormat::sRGBColorSpace : QSurfaceFormat::DefaultColorSpace); format->setStereo(stereo); } @@ -391,5 +414,10 @@ bool qglx_reduceFormat(QSurfaceFormat *format) return true; } + if (format->colorSpace() == QSurfaceFormat::sRGBColorSpace) { + format->setColorSpace(QSurfaceFormat::DefaultColorSpace); + return true; + } + return false; } diff --git a/src/platformsupport/glxconvenience/qglxconvenience_p.h b/src/platformsupport/glxconvenience/qglxconvenience_p.h index d422668584..f9647bfd9a 100644 --- a/src/platformsupport/glxconvenience/qglxconvenience_p.h +++ b/src/platformsupport/glxconvenience/qglxconvenience_p.h @@ -57,11 +57,16 @@ #include #include -QVector qglx_buildSpec(const QSurfaceFormat &format, int drawableBit = GLX_WINDOW_BIT); -XVisualInfo *qglx_findVisualInfo(Display *display, int screen, QSurfaceFormat *format, int drawableBit = GLX_WINDOW_BIT); -GLXFBConfig qglx_findConfig(Display *display, int screen, QSurfaceFormat format, bool highestPixelFormat = false, int drawableBit = GLX_WINDOW_BIT); -void qglx_surfaceFormatFromGLXFBConfig(QSurfaceFormat *format, Display *display, GLXFBConfig config); -void qglx_surfaceFormatFromVisualInfo(QSurfaceFormat *format, Display *display, XVisualInfo *visualInfo); +enum QGlxFlags +{ + QGLX_SUPPORTS_SRGB = 0x01 +}; + +QVector qglx_buildSpec(const QSurfaceFormat &format, int drawableBit = GLX_WINDOW_BIT, int flags = 0); +XVisualInfo *qglx_findVisualInfo(Display *display, int screen, QSurfaceFormat *format, int drawableBit = GLX_WINDOW_BIT, int flags = 0); +GLXFBConfig qglx_findConfig(Display *display, int screen, QSurfaceFormat format, bool highestPixelFormat = false, int drawableBit = GLX_WINDOW_BIT, int flags = 0); +void qglx_surfaceFormatFromGLXFBConfig(QSurfaceFormat *format, Display *display, GLXFBConfig config, int flags = 0); +void qglx_surfaceFormatFromVisualInfo(QSurfaceFormat *format, Display *display, XVisualInfo *visualInfo, int flags = 0); bool qglx_reduceFormat(QSurfaceFormat *format); #endif // QGLXCONVENIENCE_H diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.cpp index 8df8b28f72..61fed6f5e3 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.cpp @@ -41,6 +41,7 @@ #include "qxcbscreen.h" #include +#include QT_BEGIN_NAMESPACE @@ -58,13 +59,27 @@ const xcb_visualtype_t *QXcbGlxWindow::createVisual() QXcbScreen *scr = xcbScreen(); if (!scr) return Q_NULLPTR; - XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(scr), scr->screenNumber(), &m_format); + + qDebug(lcQpaGl) << "Requested format before FBConfig/Visual selection:" << m_format; + + const char *glxExts = glXQueryExtensionsString(DISPLAY_FROM_XCB(scr), scr->screenNumber()); + int flags = 0; + if (glxExts) { + qCDebug(lcQpaGl, "Available GLX extensions: %s", glxExts); + if (strstr(glxExts, "GLX_EXT_framebuffer_sRGB") || strstr(glxExts, "GLX_ARB_framebuffer_sRGB")) + flags |= QGLX_SUPPORTS_SRGB; + } + + XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(scr), scr->screenNumber(), &m_format, GLX_WINDOW_BIT, flags); if (!visualInfo) { qWarning() << "No XVisualInfo for format" << m_format; return Q_NULLPTR; } const xcb_visualtype_t *xcb_visualtype = scr->visualForId(visualInfo->visualid); XFree(visualInfo); + + qDebug(lcQpaGl) << "Got format:" << m_format; + return xcb_visualtype; } -- cgit v1.2.3