<table><tr><td style="">romangg added inline comments.
</td><a style="text-decoration: none; padding: 4px 8px; margin: 0 8px 8px; float: right; color: #464C5C; font-weight: bold; border-radius: 3px; background-color: #F7F7F9; background-image: linear-gradient(to bottom,#fff,#f1f0f1); display: inline-block; border: 1px solid rgba(71,87,120,.2);" href="https://phabricator.kde.org/D23105">View Revision</a></tr></table><br /><div><strong>INLINE COMMENTS</strong><div><div style="margin: 6px 0 12px 0;"><div style="border: 1px solid #C7CCD9; border-radius: 3px;"><div style="padding: 0; background: #F7F7F7; border-color: #e3e4e8; border-style: solid; border-width: 0 0 1px 0; margin: 0;"><div style="color: #74777d; background: #eff2f4; padding: 6px 8px; overflow: hidden;"><a style="float: right; text-decoration: none;" href="https://phabricator.kde.org/D23105#inline-130743">View Inline</a><span style="color: #4b4d51; font-weight: bold;">fredrik</span> wrote in <span style="color: #4b4d51; font-weight: bold;">glxbackend.cpp:718</span></div>
<div style="margin: 8px 0; padding: 0 12px; color: #74777D;"><blockquote style="border-left: 3px solid #a7b5bf; color: #464c5c; font-style: italic; margin: 4px 0 12px 0; padding: 4px 12px; background-color: #f8f9fc;"><p style="padding: 0; margin: 8px;">Ok and in other case the back buffer also has what's currently on the front buffer and we can paint it partly over and then swap?</p></blockquote>
<p style="padding: 0; margin: 8px;">No, but the buffer age extension makes it possible to query the number of frames that have elapsed since the current back buffer was the front buffer. Based on that we can calculate how much we need to repaint to bring it up-to-date.</p>
<p style="padding: 0; margin: 8px;">See <tt style="background: #ebebeb; font-size: 13px;">void OpenGLBackend::addToDamageHistory(const QRegion ®ion)</tt> and <tt style="background: #ebebeb; font-size: 13px;">QRegion OpenGLBackend::accumulatedDamageHistory(int bufferAge) const</tt></p>
<blockquote style="border-left: 3px solid #a7b5bf; color: #464c5c; font-style: italic; margin: 4px 0 12px 0; padding: 4px 12px; background-color: #f8f9fc;"><p style="padding: 0; margin: 8px;">Related to that do you know why we present() in prepareRenderingFrame (in DRM backend as well) and not after the actual paint in endRenderingFrame?</p></blockquote>
<p style="padding: 0; margin: 8px;">This code was written based on the idea that SwapBuffers() blocks until the swap is complete, which also means that it blocks until the next vblank.</p>
<p style="padding: 0; margin: 8px;">The logic can be illustrated with the following pseudo code:</p>
<div class="remarkup-code-block" style="margin: 12px 0;" data-code-lang="text" data-sigil="remarkup-code-block"><pre class="remarkup-code" style="font: 11px/15px "Menlo", "Consolas", "Monaco", monospace; padding: 12px; margin: 0; background: rgba(71, 87, 120, 0.08);">while (true) {
SwapBuffers(); // For the previous frame
renderTimer.start();
paint();
glFlush();
// Sleep until just before the next vblank
int timeSinceLastVBlank = renderTimer.elapsed();
sleep(vblankInterval - timeSinceLastVBlank);
}</pre></div>
<p style="padding: 0; margin: 8px;">In practice we don't call sleep of course; instead we start the composite timer with the timeout set to just before the next vblank, and return to the event loop.</p>
<p style="padding: 0; margin: 8px;">But the only driver where SwapBuffers() behaves like this is the NVIDIA driver, and its not the default behavior. It's enabled by setting __GL_MaxFramesAllowed to 1 before initializing OpenGL.</p>
<p style="padding: 0; margin: 8px;">The reason the next frame is rendered immediately after the buffer swap instead of doing it as late as possible is to avoid missing the vblank when there is a sudden increase in render time. Also if we miss the vblank by one millisecond, the main thread will be blocked in SwapBuffers for 15 milliseconds, which is less than ideal.</p>
<p style="padding: 0; margin: 8px;">But there's obviously a trade-off here between smoothness and latency.</p></div></div>
<div style="margin: 8px 0; padding: 0 12px;"><blockquote style="border-left: 3px solid #a7b5bf; color: #464c5c; font-style: italic; margin: 4px 0 12px 0; padding: 4px 12px; background-color: #f8f9fc;"><p style="padding: 0; margin: 8px;">The logic can be illustrated with the following pseudo code: [...]</p></blockquote>
<p style="padding: 0; margin: 8px;">Thank you very much for the comprehensive explanation. I see the logic behind it now when the SwapBuffers call is assumed to be blocking. When it's not it seems just unnecessary complicated to me. Just do the SwapBuffers directly after paint() for the next frame at some point before the upcoming vblank. Then on buffer swap event or vblank interval timer timeout repeat for the next frame.</p>
<blockquote style="border-left: 3px solid #a7b5bf; color: #464c5c; font-style: italic; margin: 4px 0 12px 0; padding: 4px 12px; background-color: #f8f9fc;"><p style="padding: 0; margin: 8px;">Also if we miss the vblank by one millisecond, the main thread will be blocked in SwapBuffers for 15 milliseconds, which is less than ideal.</p></blockquote>
<p style="padding: 0; margin: 8px;">But only if the driver blocks on SwapBuffers and as you said no current driver behaves like this per default, right? Otherwise if we miss we "just" have a delay of one frame for the next paint result on screen (what we have with the current code on master all the time).</p></div></div></div></div></div><br /><div><strong>REPOSITORY</strong><div><div>R108 KWin</div></div></div><br /><div><strong>REVISION DETAIL</strong><div><a href="https://phabricator.kde.org/D23105">https://phabricator.kde.org/D23105</a></div></div><br /><div><strong>To: </strong>romangg, KWin, fredrik<br /><strong>Cc: </strong>nicolasfella, alexeymin, kwin, LeGast00n, The-Feren-OS-Dev, sbergeron, jraleigh, fbampaloukas, GB_2, mkulinski, ragreen, jackyalcine, Pitel, iodelay, crozbo, bwowk, ZrenBot, ngraham, himcesjf, lesliezhai, ali-mohamed, hardening, romangg, jensreuterberg, abetts, sebas, apol, mart<br /></div>