kwin/plugins/platforms/x11/windowed/egl_x11_backend.cpp
Vlad Zahorodnii ef6fa25d90 platforms/x11: Split out the EGL for X11 backend
EGL for X and EGL for Wayland backends are quite different. The main
motivation behind this change is to prepare the EGL backends for
monitoring vblank events. Things work quite differently depending on
if the EGL backend renders onto a toplevel window or overlay window.
2021-01-06 16:59:29 +00:00

130 lines
3.4 KiB
C++

/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "egl_x11_backend.h"
// kwin
#include "screens.h"
#include "x11windowed_backend.h"
// kwin libs
#include <kwinglplatform.h>
namespace KWin
{
EglX11Backend::EglX11Backend(X11WindowedBackend *backend)
: EglOnXBackend(backend->connection(), backend->display(), backend->rootWindow(), backend->screenNumer(), XCB_WINDOW_NONE)
, m_backend(backend)
{
}
EglX11Backend::~EglX11Backend() = default;
void EglX11Backend::init()
{
EglOnXBackend::init();
if (!isFailed()) {
initWayland();
}
}
void EglX11Backend::cleanupSurfaces()
{
for (auto it = m_surfaces.begin(); it != m_surfaces.end(); ++it) {
eglDestroySurface(eglDisplay(), *it);
}
}
bool EglX11Backend::createSurfaces()
{
for (int i = 0; i < screens()->count(); ++i) {
EGLSurface s = createSurface(m_backend->windowForScreen(i));
if (s == EGL_NO_SURFACE) {
return false;
}
m_surfaces << s;
}
if (m_surfaces.isEmpty()) {
return false;
}
setSurface(m_surfaces.first());
return true;
}
bool EglX11Backend::usesOverlayWindow() const
{
return false;
}
QRegion EglX11Backend::beginFrame(int screenId)
{
makeContextCurrent(m_surfaces.at(screenId));
setupViewport(screenId);
return screens()->geometry(screenId);
}
void EglX11Backend::setupViewport(int screenId)
{
// TODO: ensure the viewport is set correctly each time
const QSize &overall = screens()->size();
const QRect &v = screens()->geometry(screenId);
// TODO: are the values correct?
qreal scale = screens()->scale(screenId);
glViewport(-v.x(), v.height() - overall.height() + v.y(), overall.width() * scale, overall.height() * scale);
}
void EglX11Backend::endFrame(int screenId, const QRegion &renderedRegion, const QRegion &damagedRegion)
{
Q_UNUSED(damagedRegion)
const QRect &outputGeometry = screens()->geometry(screenId);
presentSurface(m_surfaces.at(screenId), renderedRegion, outputGeometry);
}
void EglX11Backend::presentSurface(EGLSurface surface, const QRegion &damage, const QRect &screenGeometry)
{
if (damage.isEmpty()) {
return;
}
const bool fullRepaint = supportsBufferAge() || (damage == screenGeometry);
if (fullRepaint || !havePostSubBuffer()) {
// the entire screen changed, or we cannot do partial updates (which implies we enabled surface preservation)
eglSwapBuffers(eglDisplay(), surface);
} else {
// a part of the screen changed, and we can use eglPostSubBufferNV to copy the updated area
for (const QRect &r : damage) {
eglPostSubBufferNV(eglDisplay(), surface, r.left(), screenGeometry.height() - r.bottom() - 1, r.width(), r.height());
}
}
}
SceneOpenGLTexturePrivate *EglX11Backend::createBackendTexture(SceneOpenGLTexture *texture)
{
return new EglX11Texture(texture, this);
}
void EglX11Backend::screenGeometryChanged(const QSize &size)
{
Q_UNUSED(size)
}
/************************************************
* EglX11Texture
************************************************/
EglX11Texture::EglX11Texture(KWin::SceneOpenGLTexture *texture, EglX11Backend *backend)
: AbstractEglTexture(texture, backend)
{
}
EglX11Texture::~EglX11Texture()
{
}
} // namespace