Add swapInterval to QSurfaceFormat
Implement swap interval support for EGL, GLX and WGL. The environment variable QT_QPA_EGLFS_SWAPINTERVAL is renamed to QT_QPA_EGL_SWAPINTERVAL and can be used to override the applications' setting of the swap interval. Task-number: QTBUG-31939 Change-Id: I644325d5d3306b7604bffd7efccda3c00ed37d36 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com> Reviewed-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> Reviewed-by: Gunnar Sletta <gunnar.sletta@digia.com>
This commit is contained in:
parent
c784ec00fa
commit
5dd94b75e3
4
dist/changes-5.3.0
vendored
4
dist/changes-5.3.0
vendored
@ -29,3 +29,7 @@ QtCore
|
||||
|
||||
QtGui
|
||||
-----
|
||||
|
||||
- Added setSwapInterval() to QSurfaceFormat. Platforms that support
|
||||
setting the swap interval are now defaulting to the value of 1,
|
||||
meaning vsync is enabled.
|
||||
|
@ -72,6 +72,7 @@ public:
|
||||
, profile(QSurfaceFormat::NoProfile)
|
||||
, major(2)
|
||||
, minor(0)
|
||||
, swapInterval(1) // default to vsync
|
||||
{
|
||||
}
|
||||
|
||||
@ -89,7 +90,8 @@ public:
|
||||
renderableType(other->renderableType),
|
||||
profile(other->profile),
|
||||
major(other->major),
|
||||
minor(other->minor)
|
||||
minor(other->minor),
|
||||
swapInterval(other->swapInterval)
|
||||
{
|
||||
}
|
||||
|
||||
@ -107,6 +109,7 @@ public:
|
||||
QSurfaceFormat::OpenGLContextProfile profile;
|
||||
int major;
|
||||
int minor;
|
||||
int swapInterval;
|
||||
};
|
||||
|
||||
/*!
|
||||
@ -675,6 +678,46 @@ void QSurfaceFormat::setVersion(int major, int minor)
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the preferred swap interval. The swap interval specifies the
|
||||
minimum number of video frames that are displayed before a buffer
|
||||
swap occurs. This can be used to sync the GL drawing into a window
|
||||
to the vertical refresh of the screen.
|
||||
|
||||
Setting an \a interval value of 0 will turn the vertical refresh
|
||||
syncing off, any value higher than 0 will turn the vertical
|
||||
syncing on. Setting \a interval to a higher value, for example 10,
|
||||
results in having 10 vertical retraces between every buffer swap.
|
||||
|
||||
The default interval is 1.
|
||||
|
||||
Changing the swap interval may not be supported by the underlying
|
||||
platform. In this case, the request will be silently ignored.
|
||||
|
||||
\since 5.3
|
||||
|
||||
\sa swapInterval()
|
||||
*/
|
||||
void QSurfaceFormat::setSwapInterval(int interval)
|
||||
{
|
||||
if (d->swapInterval != interval) {
|
||||
detach();
|
||||
d->swapInterval = interval;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the swap interval.
|
||||
|
||||
\since 5.3
|
||||
|
||||
\sa setSwapInterval()
|
||||
*/
|
||||
int QSurfaceFormat::swapInterval() const
|
||||
{
|
||||
return d->swapInterval;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns \c true if all the options of the two QSurfaceFormat objects
|
||||
\a a and \a b are equal.
|
||||
@ -694,7 +737,8 @@ bool operator==(const QSurfaceFormat& a, const QSurfaceFormat& b)
|
||||
&& a.d->swapBehavior == b.d->swapBehavior
|
||||
&& a.d->profile == b.d->profile
|
||||
&& a.d->major == b.d->major
|
||||
&& a.d->minor == b.d->minor);
|
||||
&& a.d->minor == b.d->minor
|
||||
&& a.d->swapInterval == b.d->swapInterval);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -724,6 +768,7 @@ QDebug operator<<(QDebug dbg, const QSurfaceFormat &f)
|
||||
<< ", stencilBufferSize " << d->stencilSize
|
||||
<< ", samples " << d->numSamples
|
||||
<< ", swapBehavior " << d->swapBehavior
|
||||
<< ", swapInterval " << d->swapInterval
|
||||
<< ", profile " << d->profile
|
||||
<< ')';
|
||||
|
||||
|
@ -135,6 +135,9 @@ public:
|
||||
bool testOption(FormatOption option) const;
|
||||
QSurfaceFormat::FormatOptions options() const;
|
||||
|
||||
int swapInterval() const;
|
||||
void setSwapInterval(int interval);
|
||||
|
||||
private:
|
||||
QSurfaceFormatPrivate *d;
|
||||
|
||||
|
@ -350,6 +350,7 @@ QSurfaceFormat q_glFormatFromConfig(EGLDisplay display, const EGLConfig config,
|
||||
format.setStencilBufferSize(stencilSize);
|
||||
format.setSamples(sampleCount);
|
||||
format.setStereo(false); // EGL doesn't support stereo buffers
|
||||
format.setSwapInterval(referenceFormat.swapInterval());
|
||||
|
||||
// Clear the EGL error state because some of the above may
|
||||
// have errored out because the attribute is not applicable
|
||||
|
@ -64,6 +64,9 @@ QEGLPlatformContext::QEGLPlatformContext(const QSurfaceFormat &format, QPlatform
|
||||
: m_eglDisplay(display)
|
||||
, m_eglApi(eglApi)
|
||||
, m_eglConfig(q_configFromGLFormat(display, format))
|
||||
, m_swapInterval(-1)
|
||||
, m_swapIntervalEnvChecked(false)
|
||||
, m_swapIntervalFromEnv(-1)
|
||||
{
|
||||
init(format, share);
|
||||
}
|
||||
@ -136,6 +139,27 @@ bool QEGLPlatformContext::makeCurrent(QPlatformSurface *surface)
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ok) {
|
||||
if (!m_swapIntervalEnvChecked) {
|
||||
m_swapIntervalEnvChecked = true;
|
||||
if (qEnvironmentVariableIsSet("QT_QPA_EGL_SWAPINTERVAL")) {
|
||||
QByteArray swapIntervalString = qgetenv("QT_QPA_EGL_SWAPINTERVAL");
|
||||
bool ok;
|
||||
const int swapInterval = swapIntervalString.toInt(&ok);
|
||||
if (ok)
|
||||
m_swapIntervalFromEnv = swapInterval;
|
||||
}
|
||||
}
|
||||
const int requestedSwapInterval = m_swapIntervalFromEnv >= 0
|
||||
? m_swapIntervalFromEnv
|
||||
: surface->format().swapInterval();
|
||||
if (requestedSwapInterval >= 0 && m_swapInterval != requestedSwapInterval) {
|
||||
m_swapInterval = requestedSwapInterval;
|
||||
eglSwapInterval(eglDisplay(), m_swapInterval);
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
@ -80,6 +80,9 @@ private:
|
||||
EGLenum m_eglApi;
|
||||
EGLConfig m_eglConfig;
|
||||
QSurfaceFormat m_format;
|
||||
int m_swapInterval;
|
||||
bool m_swapIntervalEnvChecked;
|
||||
int m_swapIntervalFromEnv;
|
||||
};
|
||||
|
||||
#endif //QEGLPLATFORMCONTEXT_H
|
||||
|
@ -54,29 +54,13 @@ QT_BEGIN_NAMESPACE
|
||||
QEglFSContext::QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share,
|
||||
EGLDisplay display, EGLenum eglApi)
|
||||
: QEGLPlatformContext(QEglFSHooks::hooks()->surfaceFormatFor(format), share, display,
|
||||
QEglFSIntegration::chooseConfig(display, QEglFSHooks::hooks()->surfaceFormatFor(format)), eglApi),
|
||||
m_swapIntervalSet(false)
|
||||
QEglFSIntegration::chooseConfig(display, QEglFSHooks::hooks()->surfaceFormatFor(format)), eglApi)
|
||||
{
|
||||
}
|
||||
|
||||
bool QEglFSContext::makeCurrent(QPlatformSurface *surface)
|
||||
{
|
||||
bool success = QEGLPlatformContext::makeCurrent(surface);
|
||||
|
||||
if (success && !m_swapIntervalSet) {
|
||||
m_swapIntervalSet = true;
|
||||
int swapInterval = 1;
|
||||
QByteArray swapIntervalString = qgetenv("QT_QPA_EGLFS_SWAPINTERVAL");
|
||||
if (!swapIntervalString.isEmpty()) {
|
||||
bool ok;
|
||||
swapInterval = swapIntervalString.toInt(&ok);
|
||||
if (!ok)
|
||||
swapInterval = 1;
|
||||
}
|
||||
eglSwapInterval(eglDisplay(), swapInterval);
|
||||
}
|
||||
|
||||
return success;
|
||||
return QEGLPlatformContext::makeCurrent(surface);
|
||||
}
|
||||
|
||||
EGLSurface QEglFSContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface)
|
||||
|
@ -55,9 +55,6 @@ public:
|
||||
bool makeCurrent(QPlatformSurface *surface);
|
||||
EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface);
|
||||
void swapBuffers(QPlatformSurface *surface);
|
||||
|
||||
private:
|
||||
bool m_swapIntervalSet;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -126,7 +126,7 @@ void QEglFSWindow::create()
|
||||
EGLDisplay display = static_cast<QEglFSScreen *>(screen)->display();
|
||||
QSurfaceFormat platformFormat = QEglFSHooks::hooks()->surfaceFormatFor(window()->requestedFormat());
|
||||
m_config = QEglFSIntegration::chooseConfig(display, platformFormat);
|
||||
m_format = q_glFormatFromConfig(display, m_config);
|
||||
m_format = q_glFormatFromConfig(display, m_config, platformFormat);
|
||||
|
||||
resetSurface();
|
||||
|
||||
|
@ -880,7 +880,9 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex
|
||||
m_staticContext(staticContext),
|
||||
m_context(context),
|
||||
m_renderingContext(0),
|
||||
m_pixelFormat(0), m_extensionsUsed(false)
|
||||
m_pixelFormat(0),
|
||||
m_extensionsUsed(false),
|
||||
m_swapInterval(-1)
|
||||
{
|
||||
QSurfaceFormat format = context->format();
|
||||
if (format.renderableType() == QSurfaceFormat::DefaultRenderableType)
|
||||
@ -977,11 +979,9 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex
|
||||
|
||||
QWindowsOpenGLContextFormat::current().apply(&m_obtainedFormat);
|
||||
|
||||
if (requestedAdditional.swapInterval != -1 && m_staticContext->wglSwapInternalExt) {
|
||||
m_staticContext->wglSwapInternalExt(requestedAdditional.swapInterval);
|
||||
if (m_staticContext->wglGetSwapInternalExt)
|
||||
obtainedSwapInternal = m_staticContext->wglGetSwapInternalExt();
|
||||
}
|
||||
if (m_staticContext->wglGetSwapInternalExt)
|
||||
obtainedSwapInternal = m_staticContext->wglGetSwapInternalExt();
|
||||
|
||||
wglMakeCurrent(0, 0);
|
||||
} while (false);
|
||||
if (hdc)
|
||||
@ -1085,7 +1085,19 @@ bool QWindowsGLContext::makeCurrent(QPlatformSurface *surface)
|
||||
window->setFlag(QWindowsWindow::OpenGLDoubleBuffered);
|
||||
}
|
||||
m_windowContexts.append(newContext);
|
||||
return wglMakeCurrent(newContext.hdc, newContext.renderingContext);
|
||||
|
||||
bool success = wglMakeCurrent(newContext.hdc, newContext.renderingContext);
|
||||
|
||||
// Set the swap interval
|
||||
if (m_staticContext->wglSwapInternalExt) {
|
||||
const int interval = surface->format().swapInterval();
|
||||
if (interval >= 0 && m_swapInterval != interval) {
|
||||
m_swapInterval = interval;
|
||||
m_staticContext->wglSwapInternalExt(interval);
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void QWindowsGLContext::doneCurrent()
|
||||
|
@ -64,11 +64,10 @@ enum QWindowsGLFormatFlags
|
||||
// Additional format information for Windows.
|
||||
struct QWindowsOpenGLAdditionalFormat
|
||||
{
|
||||
QWindowsOpenGLAdditionalFormat(unsigned formatFlagsIn = 0, unsigned pixmapDepthIn = 0, unsigned swapIntervalIn = -1) :
|
||||
formatFlags(formatFlagsIn), pixmapDepth(pixmapDepthIn), swapInterval(swapIntervalIn) {}
|
||||
QWindowsOpenGLAdditionalFormat(unsigned formatFlagsIn = 0, unsigned pixmapDepthIn = 0) :
|
||||
formatFlags(formatFlagsIn), pixmapDepth(pixmapDepthIn) { }
|
||||
unsigned formatFlags; // QWindowsGLFormatFlags.
|
||||
unsigned pixmapDepth; // for QWindowsGLRenderToPixmap
|
||||
int swapInterval;
|
||||
};
|
||||
|
||||
// Per-window data for active OpenGL contexts.
|
||||
@ -178,6 +177,7 @@ private:
|
||||
PIXELFORMATDESCRIPTOR m_obtainedPixelFormatDescriptor;
|
||||
int m_pixelFormat;
|
||||
bool m_extensionsUsed;
|
||||
int m_swapInterval;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -167,6 +167,7 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat
|
||||
, m_shareContext(0)
|
||||
, m_format(format)
|
||||
, m_isPBufferCurrent(false)
|
||||
, m_swapInterval(-1)
|
||||
{
|
||||
if (m_format.renderableType() == QSurfaceFormat::DefaultRenderableType)
|
||||
m_format.setRenderableType(QSurfaceFormat::OpenGL);
|
||||
@ -326,19 +327,50 @@ QGLXContext::~QGLXContext()
|
||||
|
||||
bool QGLXContext::makeCurrent(QPlatformSurface *surface)
|
||||
{
|
||||
bool success = false;
|
||||
Q_ASSERT(surface->surface()->surfaceType() == QSurface::OpenGLSurface);
|
||||
|
||||
Display *dpy = DISPLAY_FROM_XCB(m_screen);
|
||||
GLXDrawable glxDrawable = 0;
|
||||
QSurface::SurfaceClass surfaceClass = surface->surface()->surfaceClass();
|
||||
if (surfaceClass == QSurface::Window) {
|
||||
m_isPBufferCurrent = false;
|
||||
QXcbWindow *window = static_cast<QXcbWindow *>(surface);
|
||||
return glXMakeCurrent(DISPLAY_FROM_XCB(m_screen), window->xcb_window(), m_context);
|
||||
glxDrawable = window->xcb_window();
|
||||
success = glXMakeCurrent(dpy, glxDrawable, m_context);
|
||||
} else if (surfaceClass == QSurface::Offscreen) {
|
||||
m_isPBufferCurrent = true;
|
||||
QGLXPbuffer *pbuffer = static_cast<QGLXPbuffer *>(surface);
|
||||
return glXMakeContextCurrent(DISPLAY_FROM_XCB(m_screen), pbuffer->pbuffer(), pbuffer->pbuffer(), m_context);
|
||||
glxDrawable = pbuffer->pbuffer();
|
||||
success = glXMakeContextCurrent(dpy, glxDrawable, glxDrawable, m_context);
|
||||
}
|
||||
return false;
|
||||
|
||||
if (success) {
|
||||
int interval = surface->format().swapInterval();
|
||||
if (interval >= 0 && m_swapInterval != interval) {
|
||||
m_swapInterval = interval;
|
||||
typedef void (*qt_glXSwapIntervalEXT)(Display *, GLXDrawable, int);
|
||||
typedef void (*qt_glXSwapIntervalMESA)(unsigned int);
|
||||
static qt_glXSwapIntervalEXT glXSwapIntervalEXT = 0;
|
||||
static qt_glXSwapIntervalMESA glXSwapIntervalMESA = 0;
|
||||
static bool resolved = false;
|
||||
if (!resolved) {
|
||||
resolved = true;
|
||||
QList<QByteArray> glxExt = QByteArray(glXQueryExtensionsString(dpy,
|
||||
m_screen->screenNumber())).split(' ');
|
||||
if (glxExt.contains("GLX_EXT_swap_control"))
|
||||
glXSwapIntervalEXT = (qt_glXSwapIntervalEXT) getProcAddress("glXSwapIntervalEXT");
|
||||
if (glxExt.contains("GLX_MESA_swap_control"))
|
||||
glXSwapIntervalMESA = (qt_glXSwapIntervalMESA) getProcAddress("glXSwapIntervalMESA");
|
||||
}
|
||||
if (glXSwapIntervalEXT)
|
||||
glXSwapIntervalEXT(dpy, glxDrawable, interval);
|
||||
else if (glXSwapIntervalMESA)
|
||||
glXSwapIntervalMESA(interval);
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void QGLXContext::doneCurrent()
|
||||
|
@ -78,6 +78,7 @@ private:
|
||||
GLXContext m_shareContext;
|
||||
QSurfaceFormat m_format;
|
||||
bool m_isPBufferCurrent;
|
||||
int m_swapInterval;
|
||||
};
|
||||
|
||||
|
||||
|
@ -293,7 +293,7 @@ void QXcbWindow::create()
|
||||
#elif defined(XCB_USE_EGL)
|
||||
EGLDisplay eglDisplay = connection()->egl_display();
|
||||
EGLConfig eglConfig = q_configFromGLFormat(eglDisplay, m_format, true);
|
||||
m_format = q_glFormatFromConfig(eglDisplay, eglConfig);
|
||||
m_format = q_glFormatFromConfig(eglDisplay, eglConfig, m_format);
|
||||
|
||||
VisualID id = QXlibEglIntegration::getCompatibleVisualId(DISPLAY_FROM_XCB(this), eglDisplay, eglConfig);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user