fix scheduling the repaints

repaints caused by effects so far polluted the timing calculations
since they started the timer on the old vsync offset
This (together with undercut timing) lead to multiple frames in
the buffer queue, and ultimately to a blocking swap

For unsynced painting, it simply caused wrong timings - leading to
"well, kinda around 60Hz - could be 75 as just well".

REVIEW: 112368
CCBUG: 322060
that part is fixed in 4.11.2
This commit is contained in:
Thomas Lübking 2013-08-30 01:30:13 +02:00
parent cb88bc8848
commit e63e5f5712
3 changed files with 47 additions and 6 deletions

View file

@ -270,7 +270,6 @@ void Compositor::slotCompositingOptionsInitialized()
} }
// render at least once // render at least once
compositeTimer.stop();
performCompositing(); performCompositing();
} }
@ -548,7 +547,6 @@ void Compositor::addRepaintFull()
void Compositor::timerEvent(QTimerEvent *te) void Compositor::timerEvent(QTimerEvent *te)
{ {
if (te->timerId() == compositeTimer.timerId()) { if (te->timerId() == compositeTimer.timerId()) {
compositeTimer.stop();
performCompositing(); performCompositing();
} else } else
QObject::timerEvent(te); QObject::timerEvent(te);
@ -596,10 +594,12 @@ void Compositor::performCompositing()
if (repaints_region.isEmpty() && !windowRepaintsPending()) { if (repaints_region.isEmpty() && !windowRepaintsPending()) {
m_scene->idle(); 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 // 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 // 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. // need this anymore and paints normally will also reset the suspended unredirect.
// Otherwise the window would not be painted normally anyway. // Otherwise the window would not be painted normally anyway.
compositeTimer.stop();
return; return;
} }
@ -617,6 +617,8 @@ void Compositor::performCompositing()
m_timeSinceLastVBlank = m_scene->paint(repaints, windows); 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() // 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 // 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 // scheduleRepaint() would restart it again somewhen later, called from functions that
@ -676,10 +678,29 @@ void Compositor::setCompositeTimer()
waitTime = nanoToMilli(padding - options->vBlankTime()); waitTime = nanoToMilli(padding - options->vBlankTime());
} }
} }
else // w/o vsync we just jump to the next demanded tick else { // w/o blocking 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 if (fpsInterval > m_timeSinceLastVBlank) {
// "0" would be sufficient, but the compositor isn't the WMs only task waitTime = nanoToMilli(fpsInterval - m_timeSinceLastVBlank);
waitTime = (m_timeSinceLastVBlank > fpsInterval) ? 1 : 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 compositeTimer.start(qMin(waitTime, 250u), this); // force 4fps minimum
} }

View file

@ -26,6 +26,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <kwinglplatform.h> #include <kwinglplatform.h>
// KDE // KDE
#include <KDE/KDebug> #include <KDE/KDebug>
// system
#include <unistd.h>
namespace KWin namespace KWin
{ {
@ -320,6 +322,14 @@ SceneOpenGL::TexturePrivate *EglOnXBackend::createBackendTexture(SceneOpenGL::Te
void EglOnXBackend::prepareRenderingFrame() 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(); present();
startRenderTimer(); startRenderTimer();
eglWaitNative(EGL_CORE_NATIVE_ENGINE); eglWaitNative(EGL_CORE_NATIVE_ENGINE);

View file

@ -35,6 +35,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// KDE // KDE
#include <KDE/KDebug> #include <KDE/KDebug>
#include <KDE/KXErrorHandler> #include <KDE/KXErrorHandler>
// system
#include <unistd.h>
namespace KWin namespace KWin
{ {
@ -493,6 +495,14 @@ SceneOpenGL::TexturePrivate *GlxBackend::createBackendTexture(SceneOpenGL::Textu
void GlxBackend::prepareRenderingFrame() 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(); present();
startRenderTimer(); startRenderTimer();
glXWaitX(); glXWaitX();