[wayland] Add a virtual framebuffer backend

A new backend which doesn't present the rendered output. It uses a
QPainter scene, renders to a QImage but doesn't present it anywhere.
Thus a real virtual backend.

By exporting the environment variable KWIN_WAYLAND_VIRTUAL_SCREENSHOTS
the backend creates a temporary dir, prints the path to std-out and
saves each rendered frame into that directory. Of course with exit it
will be deleted again.
This commit is contained in:
Martin Gräßlin 2015-10-02 10:44:29 +02:00
parent 007a317099
commit bfa9646d1d
10 changed files with 427 additions and 1 deletions

View file

@ -5,6 +5,7 @@ add_subdirectory(fbdev)
if(HAVE_LIBHYBRIS)
add_subdirectory(hwcomposer)
endif()
add_subdirectory(virtual)
add_subdirectory(wayland)
if(X11_XCB_FOUND)
add_subdirectory(x11)

View file

@ -0,0 +1,15 @@
set(VIRTUAL_SOURCES
virtual_backend.cpp
scene_qpainter_virtual_backend.cpp
screens_virtual.cpp
)
add_library(KWinWaylandVirtualBackend MODULE ${VIRTUAL_SOURCES})
target_link_libraries(KWinWaylandVirtualBackend kwin)
install(
TARGETS
KWinWaylandVirtualBackend
DESTINATION
${PLUGIN_INSTALL_DIR}/org.kde.kwin.waylandbackends/
)

View file

@ -0,0 +1,99 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "scene_qpainter_virtual_backend.h"
#include "virtual_backend.h"
#include "cursor.h"
#include <QDebug>
#include <QPainter>
#include <QTemporaryDir>
namespace KWin
{
VirtualQPainterBackend::VirtualQPainterBackend(VirtualBackend *backend)
: QPainterBackend()
, m_backBuffer(backend->size(), QImage::Format_RGB32)
, m_backend(backend)
{
if (qEnvironmentVariableIsSet("KWIN_WAYLAND_VIRTUAL_SCREENSHOTS")) {
m_screenshotDir.reset(new QTemporaryDir);
if (!m_screenshotDir->isValid()) {
m_screenshotDir.reset();
}
if (!m_screenshotDir.isNull()) {
qDebug() << "Screenshots saved to: " << m_screenshotDir->path();
}
}
}
VirtualQPainterBackend::~VirtualQPainterBackend() = default;
QImage *VirtualQPainterBackend::buffer()
{
return &m_backBuffer;
}
bool VirtualQPainterBackend::needsFullRepaint() const
{
return true;
}
void VirtualQPainterBackend::prepareRenderingFrame()
{
}
void VirtualQPainterBackend::screenGeometryChanged(const QSize &size)
{
if (m_backBuffer.size() != size) {
m_backBuffer = QImage(size, QImage::Format_RGB32);
m_backBuffer.fill(Qt::black);
}
}
void VirtualQPainterBackend::present(int mask, const QRegion &damage)
{
Q_UNUSED(mask)
Q_UNUSED(damage)
if (!m_screenshotDir.isNull()) {
m_backBuffer.save(QStringLiteral("%1/%2.png").arg(m_screenshotDir->path()).arg(QString::number(m_frameCounter++)));
}
}
bool VirtualQPainterBackend::usesOverlayWindow() const
{
return false;
}
void VirtualQPainterBackend::renderCursor(QPainter *painter)
{
if (!m_backend->usesSoftwareCursor()) {
return;
}
const QImage img = m_backend->softwareCursor();
if (img.isNull()) {
return;
}
const QPoint cursorPos = Cursor::pos();
const QPoint hotspot = m_backend->softwareCursorHotspot();
painter->drawImage(cursorPos - hotspot, img);
m_backend->markCursorAsRendered();
}
}

View file

@ -0,0 +1,58 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_SCENE_QPAINTER_X11_BACKEND_H
#define KWIN_SCENE_QPAINTER_X11_BACKEND_H
#include "scene_qpainter.h"
#include <QObject>
class QTemporaryDir;
namespace KWin
{
class VirtualBackend;
class VirtualQPainterBackend : public QObject, public QPainterBackend
{
Q_OBJECT
public:
VirtualQPainterBackend(VirtualBackend *backend);
virtual ~VirtualQPainterBackend();
QImage *buffer() override;
bool needsFullRepaint() const override;
bool usesOverlayWindow() const override;
void prepareRenderingFrame() override;
void present(int mask, const QRegion &damage) override;
void screenGeometryChanged(const QSize &size) override;
void renderCursor(QPainter *painter) override;
private:
QImage m_backBuffer;
VirtualBackend *m_backend;
QScopedPointer<QTemporaryDir> m_screenshotDir;
int m_frameCounter = 0;
};
}
#endif

View file

@ -0,0 +1,70 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "screens_virtual.h"
#include "virtual_backend.h"
namespace KWin
{
VirtualScreens::VirtualScreens(VirtualBackend *backend, QObject *parent)
: Screens(parent)
, m_backend(backend)
{
}
VirtualScreens::~VirtualScreens() = default;
void VirtualScreens::init()
{
KWin::Screens::init();
connect(m_backend, &VirtualBackend::sizeChanged,
this, &VirtualScreens::startChangedTimer);
updateCount();
emit changed();
}
QRect VirtualScreens::geometry(int screen) const
{
if (screen == 0) {
return QRect(QPoint(0, 0), size(screen));
}
return QRect();
}
QSize VirtualScreens::size(int screen) const
{
if (screen == 0) {
return m_backend->size();
}
return QSize();
}
void VirtualScreens::updateCount()
{
setCount(1);
}
int VirtualScreens::number(const QPoint &pos) const
{
Q_UNUSED(pos)
return 0;
}
}

View file

@ -0,0 +1,47 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_SCREENS_VIRTUAL_H
#define KWIN_SCREENS_VIRTUAL_H
#include "screens.h"
namespace KWin
{
class VirtualBackend;
class VirtualScreens : public Screens
{
Q_OBJECT
public:
VirtualScreens(VirtualBackend *backend, QObject *parent = nullptr);
virtual ~VirtualScreens();
void init() override;
QRect geometry(int screen) const override;
int number(const QPoint &pos) const override;
QSize size(int screen) const override;
void updateCount() override;
private:
VirtualBackend *m_backend;
};
}
#endif

View file

@ -0,0 +1,8 @@
{
"KPlugin": {
"Id": "KWinWaylandVirtualBackend",
"Name": "virtual",
"Description": "Render to a virtual framebuffer."
},
"input": true
}

View file

@ -0,0 +1,61 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "virtual_backend.h"
#include "scene_qpainter_virtual_backend.h"
#include "screens_virtual.h"
#include "wayland_server.h"
// KWayland
#include <KWayland/Server/seat_interface.h>
namespace KWin
{
VirtualBackend::VirtualBackend(QObject *parent)
: AbstractBackend(parent)
{
setSoftWareCursor(true);
setSupportsPointerWarping(true);
// currently only QPainter - enforce it
qputenv("KWIN_COMPOSE", QByteArrayLiteral("Q"));
}
VirtualBackend::~VirtualBackend() = default;
void VirtualBackend::init()
{
m_size = initialWindowSize();
setReady(true);
waylandServer()->seat()->setHasPointer(true);
waylandServer()->seat()->setHasKeyboard(true);
waylandServer()->seat()->setHasTouch(true);
emit screensQueried();
}
Screens *VirtualBackend::createScreens(QObject *parent)
{
return new VirtualScreens(this, parent);
}
QPainterBackend *VirtualBackend::createQPainterBackend()
{
return new VirtualQPainterBackend(this);
}
}

View file

@ -0,0 +1,59 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_X11WINDOWED_BACKEND_H
#define KWIN_X11WINDOWED_BACKEND_H
#include "abstract_backend.h"
#include <kwin_export.h>
#include <QObject>
#include <QSize>
namespace KWin
{
class KWIN_EXPORT VirtualBackend : public AbstractBackend
{
Q_OBJECT
Q_INTERFACES(KWin::AbstractBackend)
Q_PLUGIN_METADATA(IID "org.kde.kwin.AbstractBackend" FILE "virtual.json")
Q_PROPERTY(QSize size READ size NOTIFY sizeChanged)
public:
VirtualBackend(QObject *parent = nullptr);
virtual ~VirtualBackend();
void init() override;
QSize size() const {
return m_size;
}
Screens *createScreens(QObject *parent = nullptr) override;
QPainterBackend* createQPainterBackend() override;
Q_SIGNALS:
void sizeChanged();
private:
QSize m_size;
};
}
#endif

View file

@ -326,6 +326,7 @@ static const QString s_drmPlugin = QStringLiteral("KWinWaylandDrmBackend");
#if HAVE_LIBHYBRIS
static const QString s_hwcomposerPlugin = QStringLiteral("KWinWaylandHwcomposerBackend");
#endif
static const QString s_virtualPlugin = QStringLiteral("KWinWaylandVirtualBackend");
static QString automaticBackendSelection()
{
@ -411,6 +412,7 @@ int main(int argc, char * argv[])
QCommandLineOption waylandDisplayOption(QStringLiteral("wayland-display"),
i18n("The Wayland Display to use in windowed mode on platform Wayland."),
QStringLiteral("display"));
QCommandLineOption virtualFbOption(QStringLiteral("virtual"), i18n("Render to a virtual framebuffer."));
QCommandLineOption widthOption(QStringLiteral("width"),
i18n("The width for windowed mode. Default width is 1024."),
QStringLiteral("width"));
@ -437,7 +439,10 @@ int main(int argc, char * argv[])
parser.addOption(framebufferOption);
parser.addOption(framebufferDeviceOption);
}
if (hasPlugin(KWin::s_x11Plugin)) {
if (hasPlugin(KWin::s_virtualPlugin)) {
parser.addOption(virtualFbOption);
}
if (hasPlugin(KWin::s_x11Plugin) || hasPlugin(KWin::s_virtualPlugin)) {
parser.addOption(widthOption);
parser.addOption(heightOption);
}
@ -545,6 +550,9 @@ int main(int argc, char * argv[])
pluginName = KWin::s_hwcomposerPlugin;
}
#endif
if (parser.isSet(virtualFbOption)) {
pluginName = KWin::s_virtualPlugin;
}
if (pluginName.isEmpty()) {
std::cerr << "No backend specified through command line argument, trying auto resolution" << std::endl;