diff --git a/composite.cpp b/composite.cpp
index de674b6c91..4eb8e46044 100644
--- a/composite.cpp
+++ b/composite.cpp
@@ -270,7 +270,6 @@ void Compositor::slotCompositingOptionsInitialized()
}
// render at least once
- compositeTimer.stop();
performCompositing();
}
@@ -548,7 +547,6 @@ void Compositor::addRepaintFull()
void Compositor::timerEvent(QTimerEvent *te)
{
if (te->timerId() == compositeTimer.timerId()) {
- compositeTimer.stop();
performCompositing();
} else
QObject::timerEvent(te);
@@ -596,10 +594,12 @@ void Compositor::performCompositing()
if (repaints_region.isEmpty() && !windowRepaintsPending()) {
m_scene->idle();
+ m_timeSinceLastVBlank = fpsInterval - (options->vBlankTime() + 1); // means "start now"
// Note: It would seem here we should undo suspended unredirect, but when scenes need
// it for some reason, e.g. transformations or translucency, the next pass that does not
// need this anymore and paints normally will also reset the suspended unredirect.
// Otherwise the window would not be painted normally anyway.
+ compositeTimer.stop();
return;
}
@@ -617,6 +617,8 @@ void Compositor::performCompositing()
m_timeSinceLastVBlank = m_scene->paint(repaints, windows);
+ compositeTimer.stop(); // stop here to ensure *we* cause the next repaint schedule - not some effect through m_scene->paint()
+
// Trigger at least one more pass even if there would be nothing to paint, so that scene->idle()
// is called the next time. If there would be nothing pending, it will not restart the timer and
// scheduleRepaint() would restart it again somewhen later, called from functions that
@@ -676,10 +678,29 @@ void Compositor::setCompositeTimer()
waitTime = nanoToMilli(padding - options->vBlankTime());
}
}
- else // w/o vsync we just jump to the next demanded tick
- // the "1" will ensure we don't block out the eventloop - the system's just not faster
- // "0" would be sufficient, but the compositor isn't the WMs only task
- waitTime = (m_timeSinceLastVBlank > fpsInterval) ? 1 : nanoToMilli(fpsInterval - m_timeSinceLastVBlank);
+ else { // w/o blocking vsync we just jump to the next demanded tick
+ if (fpsInterval > m_timeSinceLastVBlank) {
+ waitTime = nanoToMilli(fpsInterval - m_timeSinceLastVBlank);
+ if (!waitTime) {
+ waitTime = 1; // will ensure we don't block out the eventloop - the system's just not faster ...
+ }
+ }/* else if (m_scene->syncsToVBlank() && m_timeSinceLastVBlank - fpsInterval < (vBlankInterval<<1)) {
+ // NOTICE - "for later" ------------------------------------------------------------------
+ // It can happen that we push two frames within one refresh cycle.
+ // Swapping will then block even with triple buffering when the GPU does not discard but
+ // queues frames
+ // now here's the mean part: if we take that as "OMG, we're late - next frame ASAP",
+ // there'll immediately be 2 frames in the pipe, swapping will block, we think we're
+ // late ... ewww
+ // so instead we pad to the clock again and add 2ms safety to ensure the pipe is really
+ // free
+ // NOTICE: obviously m_timeSinceLastVBlank can be too big because we're too slow as well
+ // So if this code was enabled, we'd needlessly half the framerate once more (15 instead of 30)
+ waitTime = nanoToMilli(vBlankInterval - (m_timeSinceLastVBlank - fpsInterval)%vBlankInterval) + 2;
+ }*/ else {
+ waitTime = 1; // ... "0" would be sufficient, but the compositor isn't the WMs only task
+ }
+ }
compositeTimer.start(qMin(waitTime, 250u), this); // force 4fps minimum
}
diff --git a/eglonxbackend.cpp b/eglonxbackend.cpp
index ab692d7cb5..39dd82419b 100644
--- a/eglonxbackend.cpp
+++ b/eglonxbackend.cpp
@@ -26,6 +26,8 @@ along with this program. If not, see .
#include
// KDE
#include
+// system
+#include
namespace KWin
{
@@ -320,6 +322,14 @@ SceneOpenGL::TexturePrivate *EglOnXBackend::createBackendTexture(SceneOpenGL::Te
void EglOnXBackend::prepareRenderingFrame()
{
+ if (gs_tripleBufferNeedsDetection) {
+ // the composite timer floors the repaint frequency. This can pollute our triple buffering
+ // detection because the glXSwapBuffers call for the new frame has to wait until the pending
+ // one scanned out.
+ // So we compensate for that by waiting an extra milisecond to give the driver the chance to
+ // fllush the buffer queue
+ usleep(1000);
+ }
present();
startRenderTimer();
eglWaitNative(EGL_CORE_NATIVE_ENGINE);
diff --git a/glxbackend.cpp b/glxbackend.cpp
index 9e3064c092..f1b9a6a598 100644
--- a/glxbackend.cpp
+++ b/glxbackend.cpp
@@ -35,6 +35,8 @@ along with this program. If not, see .
// KDE
#include
#include
+// system
+#include
namespace KWin
{
@@ -493,6 +495,14 @@ SceneOpenGL::TexturePrivate *GlxBackend::createBackendTexture(SceneOpenGL::Textu
void GlxBackend::prepareRenderingFrame()
{
+ if (gs_tripleBufferNeedsDetection) {
+ // the composite timer floors the repaint frequency. This can pollute our triple buffering
+ // detection because the glXSwapBuffers call for the new frame has to wait until the pending
+ // one scanned out.
+ // So we compensate for that by waiting an extra milisecond to give the driver the chance to
+ // fllush the buffer queue
+ usleep(1000);
+ }
present();
startRenderTimer();
glXWaitX();