kwin/platformsupport/scenes/opengl/backend.h
Vlad Zahorodnii b8a70e62d5 Introduce RenderLoop
At the moment, our frame scheduling infrastructure is still heavily
based on Xinerama-style rendering. Specifically, we assume that painting
is driven by a single timer, etc.

This change introduces a new type - RenderLoop. Its main purpose is to
drive compositing on a specific output, or in case of X11, on the
overlay window.

With RenderLoop, compositing is synchronized to vblank events. It
exposes the last and the next estimated presentation timestamp. The
expected presentation timestamp can be used by effects to ensure that
animations are synchronized with the upcoming vblank event.

On Wayland, every outputs has its own render loop. On X11, per screen
rendering is not possible, therefore the platform exposes the render
loop for the overlay window. Ideally, the Scene has to expose the
RenderLoop, but as the first step towards better compositing scheduling
it's good as is for the time being.

The RenderLoop tries to minimize the latency by delaying compositing as
close as possible to the next vblank event. One tricky thing about it is
that if compositing is too close to the next vblank event, animations
may become a little bit choppy. However, increasing the latency reduces
the choppiness.

Given that, there is no any "silver bullet" solution for the choppiness
issue, a new option has been added in the Compositing KCM to specify the
amount of latency. By default, it's "Medium," but if a user is not
satisfied with the upstream default, they can tweak it.
2021-01-06 16:59:29 +00:00

244 lines
7 KiB
C++

/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org>
SPDX-FileCopyrightText: 2009, 2010, 2011 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef KWIN_SCENE_OPENGL_BACKEND_H
#define KWIN_SCENE_OPENGL_BACKEND_H
#include <QRegion>
#include <kwin_export.h>
namespace KWin
{
class AbstractOutput;
class OpenGLBackend;
class OverlayWindow;
class SceneOpenGL;
class SceneOpenGLTexture;
class SceneOpenGLTexturePrivate;
class WindowPixmap;
class GLTexture;
/**
* @brief The OpenGLBackend creates and holds the OpenGL context and is responsible for Texture from Pixmap.
*
* The OpenGLBackend is an abstract base class used by the SceneOpenGL to abstract away the differences
* between various OpenGL windowing systems such as GLX and EGL.
*
* A concrete implementation has to create and release the OpenGL context in a way so that the
* SceneOpenGL does not have to care about it.
*
* In addition a major task for this class is to generate the SceneOpenGLTexturePrivate which is
* able to perform the texture from pixmap operation in the given backend.
*
* @author Martin Gräßlin <mgraesslin@kde.org>
*/
class KWIN_EXPORT OpenGLBackend
{
public:
OpenGLBackend();
virtual ~OpenGLBackend();
virtual void init() = 0;
virtual void screenGeometryChanged(const QSize &size) = 0;
virtual SceneOpenGLTexturePrivate *createBackendTexture(SceneOpenGLTexture *texture) = 0;
/**
* Notifies about starting to paint.
*
* @p damage contains the reported damage as suggested by windows and effects on prepaint calls.
*/
virtual void aboutToStartPainting(int screenId, const QRegion &damage);
virtual bool makeCurrent() = 0;
virtual void doneCurrent() = 0;
virtual bool usesOverlayWindow() const = 0;
virtual QRegion beginFrame(int screenId) = 0;
virtual void endFrame(int screenId, const QRegion &damage, const QRegion &damagedRegion) = 0;
/**
* @brief Returns the OverlayWindow used by the backend.
*
* A backend does not have to use an OverlayWindow, this is mostly for the X world.
* In case the backend does not use an OverlayWindow it is allowed to return @c null.
* It's the task of the caller to check whether it is @c null.
*
* @return :OverlayWindow*
*/
virtual OverlayWindow *overlayWindow() const;
/**
* @brief Whether the creation of the Backend failed.
*
* The SceneOpenGL should test whether the Backend got constructed correctly. If this method
* returns @c true, the SceneOpenGL should not try to start the rendering.
*
* @return bool @c true if the creation of the Backend failed, @c false otherwise.
*/
bool isFailed() const {
return m_failed;
}
/**
* @brief Whether the backend uses direct rendering.
*
* Some OpenGLScene modes require direct rendering. E.g. the OpenGL 2 should not be used
* if direct rendering is not supported by the Scene.
*
* @return bool @c true if the GL context is direct, @c false if indirect
*/
bool isDirectRendering() const {
return m_directRendering;
}
bool supportsBufferAge() const {
return m_haveBufferAge;
}
bool supportsPartialUpdate() const
{
return m_havePartialUpdate;
}
bool supportsSwapBuffersWithDamage() const
{
return m_haveSwapBuffersWithDamage;
}
bool supportsSurfacelessContext() const
{
return m_haveSurfacelessContext;
}
bool supportsNativeFence() const
{
return m_haveNativeFence;
}
/**
* Returns the damage that has accumulated since a buffer of the given age was presented.
*/
QRegion accumulatedDamageHistory(int bufferAge) const;
/**
* Saves the given region to damage history.
*/
void addToDamageHistory(const QRegion &region);
/**
* The backend specific extensions (e.g. EGL/GLX extensions).
*
* Not the OpenGL (ES) extension!
*/
QList<QByteArray> extensions() const {
return m_extensions;
}
/**
* @returns whether the backend specific extensions contains @p extension.
*/
bool hasExtension(const QByteArray &extension) const {
return m_extensions.contains(extension);
}
/**
* Copy a region of pixels from the current read to the current draw buffer
*/
void copyPixels(const QRegion &region);
virtual QSharedPointer<GLTexture> textureForOutput(AbstractOutput *output) const;
protected:
/**
* @brief Sets the backend initialization to failed.
*
* This method should be called by the concrete subclass in case the initialization failed.
* The given @p reason is logged as a warning.
*
* @param reason The reason why the initialization failed.
*/
void setFailed(const QString &reason);
/**
* @brief Sets whether the OpenGL context is direct.
*
* Should be called by the concrete subclass once it is determined whether the OpenGL context is
* direct or indirect.
* If the subclass does not call this method, the backend defaults to @c false.
*
* @param direct @c true if the OpenGL context is direct, @c false if indirect
*/
void setIsDirectRendering(bool direct) {
m_directRendering = direct;
}
void setSupportsBufferAge(bool value) {
m_haveBufferAge = value;
}
void setSupportsPartialUpdate(bool value)
{
m_havePartialUpdate = value;
}
void setSupportsSwapBuffersWithDamage(bool value)
{
m_haveSwapBuffersWithDamage = value;
}
void setSupportsSurfacelessContext(bool value)
{
m_haveSurfacelessContext = value;
}
void setSupportsNativeFence(bool value)
{
m_haveNativeFence = value;
}
/**
* Sets the platform-specific @p extensions.
*
* These are the EGL/GLX extensions, not the OpenGL extensions
*/
void setExtensions(const QList<QByteArray> &extensions) {
m_extensions = extensions;
}
private:
/**
* @brief Whether direct rendering is used, defaults to @c false.
*/
bool m_directRendering;
/**
* @brief Whether the backend supports GLX_EXT_buffer_age / EGL_EXT_buffer_age.
*/
bool m_haveBufferAge;
/**
* @brief Whether the backend supports EGL_KHR_partial_update
*/
bool m_havePartialUpdate = false;
bool m_haveSwapBuffersWithDamage = false;
/**
* @brief Whether the backend supports EGL_KHR_surfaceless_context.
*/
bool m_haveSurfacelessContext = false;
/**
* @brief Whether the backend supports EGL_ANDROID_native_fence_sync.
*/
bool m_haveNativeFence = false;
/**
* @brief Whether the initialization failed, of course default to @c false.
*/
bool m_failed;
/**
* @brief The damage history for the past 10 frames.
*/
QList<QRegion> m_damageHistory;
QList<QByteArray> m_extensions;
};
}
#endif