Revert "Remove vsync detection and configurability"
This reverts commit b3a19f9e5b
.
See: https://mail.kde.org/pipermail/kwin/2020-January/002999.html
This commit is contained in:
parent
ac05dd01c8
commit
bcf64af49b
17 changed files with 116 additions and 40 deletions
|
@ -334,12 +334,14 @@ void Compositor::startupWithWorkspace()
|
|||
setupX11Support();
|
||||
fpsInterval = options->maxFpsInterval();
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
// Sets also the 'effects' pointer.
|
||||
kwinApp()->platform()->createEffectsHandler(this, m_scene);
|
||||
|
@ -717,7 +719,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) {
|
||||
if (m_bufferSwapPending && m_scene->syncsToVBlank()) {
|
||||
m_composeAtSwapCompletion = true;
|
||||
} else {
|
||||
scheduleRepaint();
|
||||
|
@ -816,7 +818,7 @@ void Compositor::setCompositeTimer()
|
|||
waitTime = 1;
|
||||
}
|
||||
}
|
||||
/* else if (m_timeSinceLastVBlank - fpsInterval < (vBlankInterval<<1)) {
|
||||
/* 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
|
||||
|
|
|
@ -81,14 +81,16 @@ void Compositing::reset()
|
|||
auto swapStrategy = [&kwinConfig]() {
|
||||
const QString glSwapStrategyValue = kwinConfig.readEntry("GLPreferBufferSwap", "a");
|
||||
|
||||
if (glSwapStrategyValue == "a") {
|
||||
if (glSwapStrategyValue == "n") {
|
||||
return 0;
|
||||
} else if (glSwapStrategyValue == "e") {
|
||||
} else if (glSwapStrategyValue == "a") {
|
||||
return 1;
|
||||
} else if (glSwapStrategyValue == "p") {
|
||||
} else if (glSwapStrategyValue == "e") {
|
||||
return 2;
|
||||
} else if (glSwapStrategyValue == "c") {
|
||||
} else if (glSwapStrategyValue == "p") {
|
||||
return 3;
|
||||
} else if (glSwapStrategyValue == "c") {
|
||||
return 4;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
@ -284,13 +286,15 @@ void Compositing::save()
|
|||
}
|
||||
auto swapStrategy = [this] {
|
||||
switch (glSwapStrategy()) {
|
||||
case 1:
|
||||
return QStringLiteral("e");
|
||||
case 2:
|
||||
return QStringLiteral("p");
|
||||
case 3:
|
||||
return QStringLiteral("c");
|
||||
case 0:
|
||||
return QStringLiteral("n");
|
||||
case 2:
|
||||
return QStringLiteral("e");
|
||||
case 3:
|
||||
return QStringLiteral("p");
|
||||
case 4:
|
||||
return QStringLiteral("c");
|
||||
case 1:
|
||||
default:
|
||||
return QStringLiteral("a");
|
||||
}
|
||||
|
|
|
@ -165,6 +165,11 @@ 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 = 'a';
|
||||
char c = 0;
|
||||
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 = 'a';
|
||||
c = 0;
|
||||
setGlPreferBufferSwap(c);
|
||||
|
||||
m_xrenderSmoothScale = config.readEntry("XRenderSmoothScale", false);
|
||||
|
|
|
@ -570,7 +570,7 @@ public:
|
|||
return m_glPlatformInterface;
|
||||
}
|
||||
|
||||
enum GlSwapStrategy { CopyFrontBuffer = 'c', PaintFullScreen = 'p', ExtendDamage = 'e', AutoSwapStrategy = 'a' };
|
||||
enum GlSwapStrategy { NoSwapEncourage = 0, CopyFrontBuffer = 'c', PaintFullScreen = 'p', ExtendDamage = 'e', AutoSwapStrategy = 'a' };
|
||||
GlSwapStrategy glPreferBufferSwap() const {
|
||||
return m_glPreferBufferSwap;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,8 @@ namespace KWin
|
|||
{
|
||||
|
||||
OpenGLBackend::OpenGLBackend()
|
||||
: m_blocksForRetrace(false)
|
||||
: m_syncsToVBlank(false)
|
||||
, m_blocksForRetrace(false)
|
||||
, m_directRendering(false)
|
||||
, m_haveBufferAge(false)
|
||||
, m_failed(false)
|
||||
|
|
|
@ -124,6 +124,16 @@ 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
|
||||
*
|
||||
|
@ -202,6 +212,16 @@ 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
|
||||
*
|
||||
|
@ -264,6 +284,10 @@ 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,7 @@ EglGbmBackend::EglGbmBackend(DrmBackend *drmBackend)
|
|||
{
|
||||
// Egl is always direct rendering.
|
||||
setIsDirectRendering(true);
|
||||
|
||||
setSyncsToVBlank(true);
|
||||
connect(m_backend, &DrmBackend::outputAdded, this, &EglGbmBackend::createOutput);
|
||||
connect(m_backend, &DrmBackend::outputRemoved, this, &EglGbmBackend::removeOutput);
|
||||
}
|
||||
|
|
|
@ -86,6 +86,7 @@ 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,6 +30,7 @@ EglHwcomposerBackend::EglHwcomposerBackend(HwcomposerBackend *backend)
|
|||
{
|
||||
// EGL is always direct rendering
|
||||
setIsDirectRendering(true);
|
||||
setSyncsToVBlank(true);
|
||||
}
|
||||
|
||||
EglHwcomposerBackend::~EglHwcomposerBackend()
|
||||
|
|
|
@ -121,21 +121,27 @@ void EglOnXBackend::init()
|
|||
}
|
||||
}
|
||||
|
||||
setSyncsToVBlank(false);
|
||||
setBlocksForRetrace(true);
|
||||
if (surfaceHasSubPost) {
|
||||
qCDebug(KWIN_CORE) << "EGL implementation and surface support eglPostSubBufferNV, let's use it";
|
||||
|
||||
// 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";
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
qCWarning(KWIN_CORE) << "Cannot enable v-sync as max. swap interval is" << val;
|
||||
// disable v-sync
|
||||
eglSwapInterval(eglDisplay(), 0);
|
||||
}
|
||||
|
||||
} 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,6 +113,7 @@ 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
|
||||
|
@ -220,6 +221,8 @@ 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"))) {
|
||||
|
@ -229,16 +232,20 @@ void GlxBackend::init()
|
|||
setSupportsBufferAge(true);
|
||||
}
|
||||
|
||||
setSyncsToVBlank(false);
|
||||
setBlocksForRetrace(true);
|
||||
|
||||
if (m_haveEXTSwapControl) {
|
||||
glXSwapIntervalEXT(display(), glxWindow, 1);
|
||||
} else if (m_haveMESASwapControl) {
|
||||
glXSwapIntervalMESA(1);
|
||||
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";
|
||||
}
|
||||
} else {
|
||||
qCWarning(KWIN_X11STANDALONE) << "NO VSYNC! glSwapInterval is not supported";
|
||||
// disable v-sync (if possible)
|
||||
setSwapInterval(0);
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -665,6 +672,14 @@ 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())
|
||||
|
@ -678,8 +693,11 @@ void GlxBackend::present()
|
|||
if (m_haveINTELSwapEvent)
|
||||
Compositor::self()->aboutToSwapBuffers();
|
||||
|
||||
glXSwapBuffers(display(), glxWindow);
|
||||
|
||||
if (haveSwapInterval) {
|
||||
glXSwapBuffers(display(), glxWindow);
|
||||
} else {
|
||||
glXSwapBuffers(display(), glxWindow);
|
||||
}
|
||||
if (supportsBufferAge()) {
|
||||
glXQueryDrawable(display(), glxWindow, GLX_BACK_BUFFER_AGE_EXT, (GLuint *) &m_bufferAge);
|
||||
}
|
||||
|
|
|
@ -89,6 +89,7 @@ private:
|
|||
bool initRenderingContext();
|
||||
bool initFbConfig();
|
||||
void initVisualDepthHashTable();
|
||||
void setSwapInterval(int interval);
|
||||
Display *display() const {
|
||||
return m_x11Display;
|
||||
}
|
||||
|
@ -112,6 +113,7 @@ private:
|
|||
bool m_haveMESASwapControl = false;
|
||||
bool m_haveEXTSwapControl = false;
|
||||
bool m_haveINTELSwapEvent = false;
|
||||
bool haveSwapInterval = false;
|
||||
Display *m_x11Display;
|
||||
friend class GlxTexture;
|
||||
};
|
||||
|
|
|
@ -492,6 +492,11 @@ OverlayWindow *SceneOpenGL::overlayWindow() const
|
|||
return m_backend->overlayWindow();
|
||||
}
|
||||
|
||||
bool SceneOpenGL::syncsToVBlank() const
|
||||
{
|
||||
return m_backend->syncsToVBlank();
|
||||
}
|
||||
|
||||
bool SceneOpenGL::blocksForRetrace() const
|
||||
{
|
||||
return m_backend->blocksForRetrace();
|
||||
|
|
|
@ -53,6 +53,7 @@ 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;
|
||||
|
|
|
@ -626,6 +626,11 @@ bool Scene::blocksForRetrace() const
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Scene::syncsToVBlank() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void Scene::screenGeometryChanged(const QSize &size)
|
||||
{
|
||||
if (!overlayWindow()) {
|
||||
|
|
1
scene.h
1
scene.h
|
@ -146,6 +146,7 @@ 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();
|
||||
|
|
Loading…
Reference in a new issue