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:
parent
cb88bc8848
commit
e63e5f5712
3 changed files with 47 additions and 6 deletions
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in a new issue