Fix v-sync in the EGL backend

REVIEW: 109452
This commit is contained in:
Ralf Jung 2013-03-22 12:18:51 +01:00
parent 0598e6363b
commit e4ff1678ef

View file

@ -73,21 +73,38 @@ void EglOnXBackend::init()
return;
}
// TODO: activate once this is resolved. currently the explicit invocation seems pointless
#if 0
// - internet rumors say: it doesn't work with TBDR
// - eglSwapInterval has no impact on intel GMA chips
has_waitSync = options->isGlVSync();
if (has_waitSync) {
has_waitSync = (eglSwapInterval(dpy, 1) == EGL_TRUE);
if (!has_waitSync)
kWarning(1212) << "Could not activate EGL v'sync on this system";
// check for EGL_NV_post_sub_buffer and whether it can be used on the surface
if (eglPostSubBufferNV) {
if (eglQuerySurface(dpy, surface, EGL_POST_SUB_BUFFER_SUPPORTED_NV, &surfaceHasSubPost) == EGL_FALSE) {
EGLint error = eglGetError();
if (error != EGL_SUCCESS && error != EGL_BAD_ATTRIBUTE) {
setFailed("query surface failed");
return;
} else {
surfaceHasSubPost = EGL_FALSE;
}
}
}
if (!has_waitSync)
eglSwapInterval(dpy, 0); // deactivate syncing
#endif
}
if (surfaceHasSubPost) {
kDebug(1212) << "EGL implementation and surface support eglPostSubBufferNV, let's use it";
// set swap interval appropriately
const bool wantSync = options->glPreferBufferSwap() != Options::NoSwapEncourage;
const EGLBoolean res = eglSwapInterval(dpy, wantSync ? 1 : 0);
if (res && wantSync) {
kDebug(1212) << "Enabled v-sync";
setHasWaitSync(true);
}
} else {
/* In the GLX backend, we fall back to using glCopyPixels if we have no extension providing support for partial screen updates.
* However, that does not work in EGL - glCopyPixels with glDrawBuffer(GL_FRONT); does nothing.
* Hence we need EGL to preserve the backbuffer for us, so that we can draw the partial updates on it and call
* eglSwapBuffers() for each frame. eglSwapBuffers() then does the copy (no page flip possible in this mode),
* which means it is slow and not synced to the v-blank. */
kWarning(1212) << "eglPostSubBufferNV not supported, have to enable buffer preservation - which breaks v-sync and performance";
eglSurfaceAttrib(dpy, surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
}
}
bool EglOnXBackend::initRenderingContext()
{
@ -114,18 +131,6 @@ bool EglOnXBackend::initRenderingContext()
}
surface = eglCreateWindowSurface(dpy, config, overlayWindow()->window(), 0);
eglSurfaceAttrib(dpy, surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
if (eglQuerySurface(dpy, surface, EGL_POST_SUB_BUFFER_SUPPORTED_NV, &surfaceHasSubPost) == EGL_FALSE) {
EGLint error = eglGetError();
if (error != EGL_SUCCESS && error != EGL_BAD_ATTRIBUTE) {
kError(1212) << "query surface failed";
return false;
} else {
surfaceHasSubPost = EGL_FALSE;
}
}
const EGLint context_attribs[] = {
#ifdef KWIN_HAVE_OPENGLES
EGL_CONTEXT_CLIENT_VERSION, 2,
@ -199,13 +204,18 @@ void EglOnXBackend::present()
{
const QRegion displayRegion(0, 0, displayWidth(), displayHeight());
const bool fullRepaint = (lastDamage() == displayRegion);
if (fullRepaint || !(surfaceHasSubPost && eglPostSubBufferNV)) {
if (fullRepaint || !surfaceHasSubPost) {
// the entire screen changed, or we cannot do partial updates (which implies we enabled surface preservation)
eglSwapBuffers(dpy, surface);
} else {
const QRect damageRect = lastDamage().boundingRect();
eglPostSubBufferNV(dpy, surface, damageRect.left(), displayHeight() - damageRect.bottom() - 1, damageRect.width(), damageRect.height());
// a part of the screen changed, and we can use eglPostSubBufferNV to copy the updated area
foreach (const QRect & r, lastDamage().rects()) {
eglPostSubBufferNV(dpy, surface, r.left(), displayHeight() - r.bottom() - 1, r.width(), r.height());
}
}
setLastDamage(QRegion());
eglWaitGL();
xcb_flush(connection());
}
@ -226,6 +236,7 @@ void EglOnXBackend::prepareRenderingFrame()
{
if (!lastDamage().isEmpty())
present();
eglWaitNative(EGL_CORE_NATIVE_ENGINE);
startRenderTimer();
}