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();