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 <andy.nichols@qt.io>
This commit is contained in:
parent
d5078161aa
commit
931e4ae665
@ -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
|
||||
<< ')';
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -76,7 +76,11 @@ enum {
|
||||
#undef FontChange
|
||||
#endif
|
||||
|
||||
QVector<int> qglx_buildSpec(const QSurfaceFormat &format, int drawableBit)
|
||||
#ifndef GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB
|
||||
#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2
|
||||
#endif
|
||||
|
||||
QVector<int> qglx_buildSpec(const QSurfaceFormat &format, int drawableBit, int flags)
|
||||
{
|
||||
QVector<int> spec;
|
||||
|
||||
@ -120,6 +124,10 @@ QVector<int> 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 <class T>
|
||||
using QXlibArrayPointer = QScopedArrayPointer<T, QXlibScopedPointerDeleter<T>>;
|
||||
}
|
||||
|
||||
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<int> spec = qglx_buildSpec(format, drawableBit);
|
||||
const QVector<int> spec = qglx_buildSpec(format, drawableBit, flags);
|
||||
|
||||
int confcount = 0;
|
||||
QXlibArrayPointer<GLXFBConfig> 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<XVisualInfo> 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<int> attribs = qglx_buildSpec(*format, drawableBit);
|
||||
QVector<int> 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;
|
||||
}
|
||||
|
@ -57,11 +57,16 @@
|
||||
#include <X11/Xlib.h>
|
||||
#include <GL/glx.h>
|
||||
|
||||
QVector<int> 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<int> 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
|
||||
|
@ -41,6 +41,7 @@
|
||||
|
||||
#include "qxcbscreen.h"
|
||||
#include <QtGlxSupport/private/qglxconvenience_p.h>
|
||||
#include <QDebug>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user