Commit b3a19f9e authored by Roman Gilg's avatar Roman Gilg
Browse files

Remove vsync detection and configurability

Summary:
Selecting not to vsync does not make sense for an X11 compositor. In the end
we want clients to be able to present async if they want to but the compositor
is supposed to send swaps with vsync to the XServer in order to not generate
tearing artifacts.

There was also a detection logic which did some questionable things in case
vsync was not available. I don't think this is necessary at all since we can
just always run a timer to present with or without vsync.

Test Plan: kwin_x11 tested on i915.

Reviewers: #kwin, zzag

Subscribers: zzag, kwin

Tags: #kwin

Maniphest Tasks: T11071

Differential Revision: https://phabricator.kde.org/D23511
parent 285adc19
......@@ -334,14 +334,12 @@ void Compositor::startupWithWorkspace()
setupX11Support();
fpsInterval = options->maxFpsInterval();
if (m_scene->syncsToVBlank()) {
// If we do vsync, set the fps to the next multiple of the vblank rate.
vBlankInterval = milliToNano(1000) / currentRefreshRate();
fpsInterval = qMax((fpsInterval / vBlankInterval) * vBlankInterval, vBlankInterval);
} else {
// No vsync - DO NOT set "0", would cause div-by-zero segfaults.
vBlankInterval = milliToNano(1);
}
const auto rate = currentRefreshRate();
Q_ASSERT(rate != 0); // There is a fallback in options.cpp, so why check at all?
// If we do vsync, set the fps to the next multiple of the vblank rate.
vBlankInterval = milliToNano(1000) / currentRefreshRate();
fpsInterval = qMax((fpsInterval / vBlankInterval) * vBlankInterval, vBlankInterval);
// Sets also the 'effects' pointer.
kwinApp()->platform()->createEffectsHandler(this, m_scene);
......@@ -719,7 +717,7 @@ void Compositor::performCompositing()
// 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
// would again add something pending.
if (m_bufferSwapPending && m_scene->syncsToVBlank()) {
if (m_bufferSwapPending) {
m_composeAtSwapCompletion = true;
} else {
scheduleRepaint();
......@@ -818,7 +816,7 @@ void Compositor::setCompositeTimer()
waitTime = 1;
}
}
/* else if (m_scene->syncsToVBlank() && m_timeSinceLastVBlank - fpsInterval < (vBlankInterval<<1)) {
/* else if (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
......
......@@ -81,16 +81,14 @@ void Compositing::reset()
auto swapStrategy = [&kwinConfig]() {
const QString glSwapStrategyValue = kwinConfig.readEntry("GLPreferBufferSwap", "a");
if (glSwapStrategyValue == "n") {
if (glSwapStrategyValue == "a") {
return 0;
} else if (glSwapStrategyValue == "a") {
return 1;
} else if (glSwapStrategyValue == "e") {
return 2;
return 1;
} else if (glSwapStrategyValue == "p") {
return 3;
return 2;
} else if (glSwapStrategyValue == "c") {
return 4;
return 3;
}
return 0;
};
......@@ -286,15 +284,13 @@ void Compositing::save()
}
auto swapStrategy = [this] {
switch (glSwapStrategy()) {
case 0:
return QStringLiteral("n");
case 2:
case 1:
return QStringLiteral("e");
case 3:
case 2:
return QStringLiteral("p");
case 4:
case 3:
return QStringLiteral("c");
case 1:
case 0:
default:
return QStringLiteral("a");
}
......
......@@ -165,11 +165,6 @@ Alternatively, you might want to use the XRender backend instead.</string>
</item>
<item row="10" column="1">
<widget class="QComboBox" name="tearingPrevention">
<item>
<property name="text">
<string>Never</string>
</property>
</item>
<item>
<property name="text">
<string>Automatic</string>
......
......@@ -918,12 +918,12 @@ void Options::reloadCompositingSettings(bool force)
}
setGLCoreProfile(config.readEntry("GLCore", Options::defaultGLCoreProfile()));
char c = 0;
char c = 'a';
const QString s = config.readEntry("GLPreferBufferSwap", QString(Options::defaultGlPreferBufferSwap()));
if (!s.isEmpty())
c = s.at(0).toLatin1();
if (c != 'a' && c != 'c' && c != 'p' && c != 'e')
c = 0;
c = 'a';
setGlPreferBufferSwap(c);
m_xrenderSmoothScale = config.readEntry("XRenderSmoothScale", false);
......
......@@ -570,7 +570,7 @@ public:
return m_glPlatformInterface;
}
enum GlSwapStrategy { NoSwapEncourage = 0, CopyFrontBuffer = 'c', PaintFullScreen = 'p', ExtendDamage = 'e', AutoSwapStrategy = 'a' };
enum GlSwapStrategy { CopyFrontBuffer = 'c', PaintFullScreen = 'p', ExtendDamage = 'e', AutoSwapStrategy = 'a' };
GlSwapStrategy glPreferBufferSwap() const {
return m_glPreferBufferSwap;
}
......
......@@ -30,8 +30,7 @@ namespace KWin
{
OpenGLBackend::OpenGLBackend()
: m_syncsToVBlank(false)
, m_blocksForRetrace(false)
: m_blocksForRetrace(false)
, m_directRendering(false)
, m_haveBufferAge(false)
, m_failed(false)
......
......@@ -124,16 +124,6 @@ public:
bool isFailed() const {
return m_failed;
}
/**
* @brief Whether the Backend provides VSync.
*
* Currently only the GLX backend can provide VSync.
*
* @return bool @c true if VSync support is available, @c false otherwise
*/
bool syncsToVBlank() const {
return m_syncsToVBlank;
}
/**
* @brief Whether VSync blocks execution until the screen is in the retrace
*
......@@ -212,16 +202,6 @@ protected:
* @param reason The reason why the initialization failed.
*/
void setFailed(const QString &reason);
/**
* @brief Sets whether the backend provides VSync.
*
* Should be called by the concrete subclass once it is determined whether VSync is supported.
* If the subclass does not call this method, the backend defaults to @c false.
* @param enabled @c true if VSync support available, @c false otherwise.
*/
void setSyncsToVBlank(bool enabled) {
m_syncsToVBlank = enabled;
}
/**
* @brief Sets whether the VSync iplementation blocks
*
......@@ -284,10 +264,6 @@ protected:
}
private:
/**
* @brief Whether VSync is available and used, defaults to @c false.
*/
bool m_syncsToVBlank;
/**
* @brief Whether present() will block execution until the next vertical retrace @c false.
*/
......
......@@ -42,7 +42,6 @@ EglGbmBackend::EglGbmBackend(DrmBackend *b)
{
// Egl is always direct rendering
setIsDirectRendering(true);
setSyncsToVBlank(true);
connect(m_backend, &DrmBackend::outputAdded, this, &EglGbmBackend::createOutput);
connect(m_backend, &DrmBackend::outputRemoved, this,
[this] (DrmOutput *output) {
......
......@@ -86,7 +86,6 @@ EglStreamBackend::EglStreamBackend(DrmBackend *b)
: AbstractEglBackend(), m_backend(b)
{
setIsDirectRendering(true);
setSyncsToVBlank(true);
connect(m_backend, &DrmBackend::outputAdded, this, &EglStreamBackend::createOutput);
connect(m_backend, &DrmBackend::outputRemoved, this,
[this] (DrmOutput *output) {
......
......@@ -30,7 +30,6 @@ EglHwcomposerBackend::EglHwcomposerBackend(HwcomposerBackend *backend)
{
// EGL is always direct rendering
setIsDirectRendering(true);
setSyncsToVBlank(true);
setBlocksForRetrace(true);
}
......
......@@ -121,27 +121,21 @@ void EglOnXBackend::init()
}
}
setSyncsToVBlank(false);
setBlocksForRetrace(true);
if (surfaceHasSubPost) {
qCDebug(KWIN_CORE) << "EGL implementation and surface support eglPostSubBufferNV, let's use it";
if (options->glPreferBufferSwap() != Options::NoSwapEncourage) {
// check if swap interval 1 is supported
EGLint val;
eglGetConfigAttrib(eglDisplay(), config(), EGL_MAX_SWAP_INTERVAL, &val);
if (val >= 1) {
if (eglSwapInterval(eglDisplay(), 1)) {
qCDebug(KWIN_CORE) << "Enabled v-sync";
setSyncsToVBlank(true);
}
} else {
qCWarning(KWIN_CORE) << "Cannot enable v-sync as max. swap interval is" << val;
// check if swap interval 1 is supported
EGLint val;
eglGetConfigAttrib(eglDisplay(), config(), EGL_MAX_SWAP_INTERVAL, &val);
if (val >= 1) {
if (eglSwapInterval(eglDisplay(), 1)) {
qCDebug(KWIN_CORE) << "Enabled v-sync";
}
} else {
// disable v-sync
eglSwapInterval(eglDisplay(), 0);
qCWarning(KWIN_CORE) << "Cannot enable v-sync as max. swap interval is" << val;
}
} else {
/* In the GLX backend, we fall back to using glCopyPixels if we have no extension providing support for partial screen updates.
* However, that does not work in EGL - glCopyPixels with glDrawBuffer(GL_FRONT); does nothing.
......
......@@ -113,7 +113,6 @@ GlxBackend::GlxBackend(Display *display)
, glxWindow(None)
, ctx(nullptr)
, m_bufferAge(0)
, haveSwapInterval(false)
, m_x11Display(display)
{
// Ensures calls to glXSwapBuffers will always block until the next
......@@ -221,8 +220,6 @@ void GlxBackend::init()
glXSelectEvent(display(), glxWindow, GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK);
}
haveSwapInterval = m_haveMESASwapControl || m_haveEXTSwapControl;
setSupportsBufferAge(false);
if (hasExtension(QByteArrayLiteral("GLX_EXT_buffer_age"))) {
......@@ -232,20 +229,16 @@ void GlxBackend::init()
setSupportsBufferAge(true);
}
setSyncsToVBlank(false);
setBlocksForRetrace(true);
const bool wantSync = options->glPreferBufferSwap() != Options::NoSwapEncourage;
if (wantSync && glXIsDirect(display(), ctx)) {
if (haveSwapInterval) { // glXSwapInterval is preferred being more reliable
setSwapInterval(1);
setSyncsToVBlank(true);
} else {
qCWarning(KWIN_X11STANDALONE) << "NO VSYNC! glSwapInterval is not supported";
}
if (m_haveEXTSwapControl) {
glXSwapIntervalEXT(display(), glxWindow, 1);
} else if (m_haveMESASwapControl) {
glXSwapIntervalMESA(1);
} else {
// disable v-sync (if possible)
setSwapInterval(0);
qCWarning(KWIN_X11STANDALONE) << "NO VSYNC! glSwapInterval is not supported";
}
if (glPlatform->isVirtualBox()) {
// VirtualBox does not support glxQueryDrawable
// this should actually be in kwinglutils_funcs, but QueryDrawable seems not to be provided by an extension
......@@ -672,14 +665,6 @@ FBConfigInfo *GlxBackend::infoForVisual(xcb_visualid_t visual)
return info;
}
void GlxBackend::setSwapInterval(int interval)
{
if (m_haveEXTSwapControl)
glXSwapIntervalEXT(display(), glxWindow, interval);
else if (m_haveMESASwapControl)
glXSwapIntervalMESA(interval);
}
void GlxBackend::present()
{
if (lastDamage().isEmpty())
......@@ -693,11 +678,8 @@ void GlxBackend::present()
if (m_haveINTELSwapEvent)
Compositor::self()->aboutToSwapBuffers();
if (haveSwapInterval) {
glXSwapBuffers(display(), glxWindow);
} else {
glXSwapBuffers(display(), glxWindow);
}
glXSwapBuffers(display(), glxWindow);
if (supportsBufferAge()) {
glXQueryDrawable(display(), glxWindow, GLX_BACK_BUFFER_AGE_EXT, (GLuint *) &m_bufferAge);
}
......
......@@ -89,7 +89,6 @@ private:
bool initRenderingContext();
bool initFbConfig();
void initVisualDepthHashTable();
void setSwapInterval(int interval);
Display *display() const {
return m_x11Display;
}
......@@ -113,7 +112,6 @@ private:
bool m_haveMESASwapControl = false;
bool m_haveEXTSwapControl = false;
bool m_haveINTELSwapEvent = false;
bool haveSwapInterval = false;
Display *m_x11Display;
friend class GlxTexture;
};
......
......@@ -525,11 +525,6 @@ OverlayWindow *SceneOpenGL::overlayWindow() const
return m_backend->overlayWindow();
}
bool SceneOpenGL::syncsToVBlank() const
{
return m_backend->syncsToVBlank();
}
bool SceneOpenGL::blocksForRetrace() const
{
return m_backend->blocksForRetrace();
......
......@@ -54,7 +54,6 @@ public:
OverlayWindow *overlayWindow() const override;
bool usesOverlayWindow() const override;
bool blocksForRetrace() const override;
bool syncsToVBlank() const override;
bool makeOpenGLContextCurrent() override;
void doneOpenGLContextCurrent() override;
Decoration::Renderer *createDecorationRenderer(Decoration::DecoratedClientImpl *impl) override;
......
......@@ -632,11 +632,6 @@ bool Scene::blocksForRetrace() const
return false;
}
bool Scene::syncsToVBlank() const
{
return false;
}
void Scene::screenGeometryChanged(const QSize &size)
{
if (!overlayWindow()) {
......
......@@ -146,7 +146,6 @@ public:
// there's nothing to paint (adjust time_diff later)
virtual void idle();
virtual bool blocksForRetrace() const;
virtual bool syncsToVBlank() const;
virtual OverlayWindow* overlayWindow() const = 0;
virtual bool makeOpenGLContextCurrent();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment