kwin/src/backends/drm/egl_multi_backend.cpp
Vlad Zahorodnii 7228e9aefd Unify beginFrame() and endFrame() hooks for OpenGL and QPainter backends
This unifies frame hooks for OpenGL and QPainter render backends. There
are a couple of reasons why it's a good idea - it provides one mental
framework to start painting a frame, the Compositor will be able to
start and submit frames. The last one is very cool because it gives the
Compositor more power over compositing.

Besides unifying frame hooks, this cleans up a bit the arg naming mess
in endFrame(). As is, "damage" and "damagedRegion" are very confusing
names. "damage" arg has been renamed to "renderedRegion," because that's
what it is. The renderedRegion arg specifies the region that has been
repainted by the Scene. It's different from the damagedRegion as that
one specifies the surface damage, i.e. the difference between the
current and the next frame, while the renderedRegion may include a
region that had to be repainted to repair the back buffer. The main
reason why we need renderedRegion is the X11 platform. On Wayland, it's
unused.

In the future, we will need to extend this api with output layers.
2021-11-16 10:43:56 +00:00

131 lines
3.5 KiB
C++

/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2020 Xaver Hugl <xaver.hugl@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "egl_multi_backend.h"
#include <config-kwin.h>
#include "logging.h"
#include "egl_gbm_backend.h"
#include "drm_backend.h"
#include "drm_gpu.h"
namespace KWin
{
EglMultiBackend::EglMultiBackend(DrmBackend *backend, EglGbmBackend *primaryEglBackend)
: OpenGLBackend()
, m_platform(backend)
{
connect(m_platform, &DrmBackend::gpuAdded, this, &EglMultiBackend::addGpu);
connect(m_platform, &DrmBackend::gpuRemoved, this, &EglMultiBackend::removeGpu);
m_backends.append(primaryEglBackend);
setIsDirectRendering(true);
}
EglMultiBackend::~EglMultiBackend()
{
for (int i = 1; i < m_backends.count(); i++) {
delete m_backends[i];
}
// delete primary backend last, or this will crash!
delete m_backends[0];
}
void EglMultiBackend::init()
{
for (auto b : qAsConst(m_backends)) {
b->init();
}
// we only care about the rendering GPU
setSupportsBufferAge(m_backends[0]->supportsBufferAge());
setSupportsPartialUpdate(m_backends[0]->supportsPartialUpdate());
setSupportsSwapBuffersWithDamage(m_backends[0]->supportsSwapBuffersWithDamage());
// these are client extensions and the same for all egl backends
setExtensions(m_backends[0]->extensions());
m_backends[0]->makeCurrent();
m_initialized = true;
}
QRegion EglMultiBackend::beginFrame(AbstractOutput *output)
{
return findBackend(output)->beginFrame(output);
}
void EglMultiBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion)
{
findBackend(output)->endFrame(output, renderedRegion, damagedRegion);
}
bool EglMultiBackend::scanout(AbstractOutput *output, SurfaceItem *surfaceItem)
{
return findBackend(output)->scanout(output, surfaceItem);
}
bool EglMultiBackend::makeCurrent()
{
return m_backends[0]->makeCurrent();
}
void EglMultiBackend::doneCurrent()
{
m_backends[0]->doneCurrent();
}
SurfaceTexture *EglMultiBackend::createSurfaceTextureInternal(SurfacePixmapInternal *pixmap)
{
return m_backends[0]->createSurfaceTextureInternal(pixmap);
}
SurfaceTexture *EglMultiBackend::createSurfaceTextureWayland(SurfacePixmapWayland *pixmap)
{
return m_backends[0]->createSurfaceTextureWayland(pixmap);
}
QSharedPointer<GLTexture> EglMultiBackend::textureForOutput(AbstractOutput *requestedOutput) const
{
// this assumes that all outputs are rendered on backend 0
return m_backends[0]->textureForOutput(requestedOutput);
}
EglGbmBackend *EglMultiBackend::findBackend(AbstractOutput *output) const
{
for (int i = 1; i < m_backends.count(); i++) {
if (m_backends[i]->hasOutput(output)) {
return m_backends[i];
}
}
return m_backends[0];
}
bool EglMultiBackend::directScanoutAllowed(AbstractOutput *output) const
{
return findBackend(output)->directScanoutAllowed(output);
}
void EglMultiBackend::addGpu(DrmGpu *gpu)
{
EglGbmBackend *backend= new EglGbmBackend(m_platform, gpu);
if (m_initialized) {
backend->init();
}
m_backends.append(backend);
}
void EglMultiBackend::removeGpu(DrmGpu *gpu)
{
auto it = std::find_if(m_backends.begin(), m_backends.end(), [gpu](const auto &backend) {
return backend->gpu() == gpu;
});
if (it != m_backends.end()) {
delete *it;
m_backends.erase(it);
}
}
}