Commit 994c5c24 authored by Vlad Zahorodnii's avatar Vlad Zahorodnii
Browse files

Drop fbdev backend

fbdev has been deprecated and unmaintained for a while. With Linux 5.14
including SimpleDRM driver, we can drop it. (at the time of writing this
commit message, the latest Linux version is 5.16).
parent 39160e7d
Pipeline #151249 passed with stage
in 27 minutes and 50 seconds
......@@ -360,15 +360,6 @@ check_include_files(malloc.h HAVE_MALLOC_H)
check_include_file("sys/sysmacros.h" HAVE_SYS_SYSMACROS_H)
check_include_file("linux/vt.h" HAVE_LINUX_VT_H)
add_feature_info("linux/vt.h"
HAVE_LINUX_VT_H
"Required for virtual terminal support under wayland")
check_include_file("linux/fb.h" HAVE_LINUX_FB_H)
add_feature_info("linux/fb.h"
HAVE_LINUX_FB_H
"Required for the fbdev backend")
check_symbol_exists(SCHED_RESET_ON_FORK "sched.h" HAVE_SCHED_RESET_ON_FORK)
add_feature_info("SCHED_RESET_ON_FORK"
HAVE_SCHED_RESET_ON_FORK
......
add_subdirectory(drm)
add_subdirectory(fakeinput)
if (HAVE_LINUX_FB_H)
add_subdirectory(fbdev)
endif()
add_subdirectory(libinput)
add_subdirectory(virtual)
add_subdirectory(wayland)
......
set(FBDEV_SOURCES
fb_backend.cpp
logging.cpp
scene_qpainter_fb_backend.cpp
)
add_library(KWinWaylandFbdevBackend MODULE ${FBDEV_SOURCES})
set_target_properties(KWinWaylandFbdevBackend PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/org.kde.kwin.waylandbackends/")
target_link_libraries(KWinWaylandFbdevBackend kwin)
install(
TARGETS
KWinWaylandFbdevBackend
DESTINATION
${KDE_INSTALL_PLUGINDIR}/org.kde.kwin.waylandbackends/
)
/*
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 "fb_backend.h"
#include "backends/libinput/libinputbackend.h"
#include "composite.h"
#include "logging.h"
#include "main.h"
#include "platform.h"
#include "renderloop_p.h"
#include "scene_qpainter_fb_backend.h"
#include "session.h"
#include "softwarevsyncmonitor.h"
#include "udev.h"
// system
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
// Linux
#include <linux/fb.h>
namespace KWin
{
FramebufferOutput::FramebufferOutput(QObject *parent)
: AbstractWaylandOutput(parent)
, m_renderLoop(new RenderLoop(this))
{
setName("FB-0");
if (!m_vsyncMonitor) {
SoftwareVsyncMonitor *monitor = SoftwareVsyncMonitor::create(this);
monitor->setRefreshRate(m_renderLoop->refreshRate());
connect(m_renderLoop, &RenderLoop::refreshRateChanged, this, [this, monitor]() {
monitor->setRefreshRate(m_renderLoop->refreshRate());
});
m_vsyncMonitor = monitor;
}
connect(m_vsyncMonitor, &VsyncMonitor::vblankOccurred, this, &FramebufferOutput::vblank);
}
RenderLoop *FramebufferOutput::renderLoop() const
{
return m_renderLoop;
}
VsyncMonitor *FramebufferOutput::vsyncMonitor() const
{
return m_vsyncMonitor;
}
void FramebufferOutput::init(const QSize &pixelSize, const QSize &physicalSize)
{
const int refreshRate = 60000; // TODO: get actual refresh rate of fb device?
m_renderLoop->setRefreshRate(refreshRate);
Mode mode;
mode.id = 0;
mode.size = pixelSize;
mode.flags = ModeFlag::Current;
mode.refreshRate = refreshRate;
initialize("model_TODO", "manufacturer_TODO", "eisa_TODO", "serial_TODO", physicalSize, { mode }, {});
}
void FramebufferOutput::vblank(std::chrono::nanoseconds timestamp)
{
RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(m_renderLoop);
renderLoopPrivate->notifyFrameCompleted(timestamp);
}
FramebufferBackend::FramebufferBackend(QObject *parent)
: Platform(parent)
, m_session(Session::create(this))
{
setSupportsPointerWarping(true);
}
FramebufferBackend::~FramebufferBackend()
{
unmap();
if (m_fd >= 0) {
close(m_fd);
}
}
InputBackend *FramebufferBackend::createInputBackend()
{
return new LibinputBackend(this);
}
QPainterBackend *FramebufferBackend::createQPainterBackend()
{
return new FramebufferQPainterBackend(this);
}
Session *FramebufferBackend::session() const
{
return m_session;
}
bool FramebufferBackend::initialize()
{
QString framebufferDevice = deviceIdentifier();
if (framebufferDevice.isEmpty()) {
const auto fbs = Udev().listFramebuffers();
if (fbs.size() > 0) {
framebufferDevice = fbs.at(0)->devNode();
}
}
int fd = open(framebufferDevice.toUtf8().constData(), O_RDWR | O_CLOEXEC);
qCDebug(KWIN_FB) << "Using frame buffer device:" << framebufferDevice;
if (fd < 0) {
qCWarning(KWIN_FB) << "failed to open frame buffer device:" << framebufferDevice;
return false;
}
m_fd = fd;
if (!handleScreenInfo()) {
qCWarning(KWIN_FB) << "failed to handle framebuffer information";
return false;
}
initImageFormat();
if (m_imageFormat == QImage::Format_Invalid) {
return false;
}
setReady(true);
Q_EMIT screensQueried();
return true;
}
int FramebufferBackend::fileDescriptor() const
{
return m_fd;
}
bool FramebufferBackend::handleScreenInfo()
{
if (m_fd < 0) {
return false;
}
fb_var_screeninfo varinfo;
fb_fix_screeninfo fixinfo;
// Probe the device for screen information.
if (ioctl(m_fd, FBIOGET_FSCREENINFO, &fixinfo) < 0 || ioctl(m_fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
return false;
}
// Activate the framebuffer device, assuming this is a non-primary framebuffer device
varinfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
ioctl(m_fd, FBIOPUT_VSCREENINFO, &varinfo);
// Probe the device for new screen information.
if (ioctl(m_fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
return false;
}
auto *output = new FramebufferOutput;
output->init(QSize(varinfo.xres, varinfo.yres), QSize(varinfo.width, varinfo.height));
m_outputs << output;
Q_EMIT outputAdded(output);
Q_EMIT outputEnabled(output);
m_id = QByteArray(fixinfo.id);
m_red = {varinfo.red.offset, varinfo.red.length};
m_green = {varinfo.green.offset, varinfo.green.length};
m_blue = {varinfo.blue.offset, varinfo.blue.length};
m_alpha = {varinfo.transp.offset, varinfo.transp.length};
m_bitsPerPixel = varinfo.bits_per_pixel;
m_bufferLength = fixinfo.smem_len;
m_bytesPerLine = fixinfo.line_length;
return true;
}
void FramebufferBackend::map()
{
if (m_memory) {
// already mapped;
return;
}
if (m_fd < 0) {
// not valid
return;
}
void *mem = mmap(nullptr, m_bufferLength, PROT_WRITE, MAP_SHARED, m_fd, 0);
if (mem == MAP_FAILED) {
qCWarning(KWIN_FB) << "Failed to mmap frame buffer";
return;
}
m_memory = mem;
}
void FramebufferBackend::unmap()
{
if (!m_memory) {
return;
}
if (munmap(m_memory, m_bufferLength) < 0) {
qCWarning(KWIN_FB) << "Failed to munmap frame buffer";
}
m_memory = nullptr;
}
QSize FramebufferBackend::screenSize() const
{
if (m_outputs.isEmpty()) {
return QSize();
}
return m_outputs[0]->pixelSize();
}
QImage::Format FramebufferBackend::imageFormat() const
{
return m_imageFormat;
}
void FramebufferBackend::initImageFormat()
{
if (m_fd < 0) {
return;
}
qCDebug(KWIN_FB) << "Bits Per Pixel: " << m_bitsPerPixel;
qCDebug(KWIN_FB) << "Buffer Length: " << m_bufferLength;
qCDebug(KWIN_FB) << "Bytes Per Line: " << m_bytesPerLine;
qCDebug(KWIN_FB) << "Alpha Length: " << m_alpha.length;
qCDebug(KWIN_FB) << "Red Length: " << m_red.length;
qCDebug(KWIN_FB) << "Green Length: " << m_green.length;
qCDebug(KWIN_FB) << "Blue Length: " << m_blue.length;
qCDebug(KWIN_FB) << "Blue Offset: " << m_blue.offset;
qCDebug(KWIN_FB) << "Green Offset: " << m_green.offset;
qCDebug(KWIN_FB) << "Red Offset: " << m_red.offset;
qCDebug(KWIN_FB) << "Alpha Offset: " << m_alpha.offset;
if (m_bitsPerPixel == 32 &&
m_red.length == 8 &&
m_green.length == 8 &&
m_blue.length == 8 &&
m_blue.offset == 0 &&
m_green.offset == 8 &&
m_red.offset == 16) {
qCDebug(KWIN_FB) << "Framebuffer format is RGB32";
m_imageFormat = QImage::Format_RGB32;
} else if (m_bitsPerPixel == 32 &&
m_red.length == 8 &&
m_green.length == 8 &&
m_blue.length == 8 &&
m_alpha.length == 8 &&
m_red.offset == 0 &&
m_green.offset == 8 &&
m_blue.offset == 16 &&
m_alpha.offset == 24) {
qCDebug(KWIN_FB) << "Framebuffer format is RGBA8888";
m_imageFormat = QImage::Format_RGBA8888;
} else if (m_bitsPerPixel == 24 &&
m_red.length == 8 &&
m_green.length == 8 &&
m_blue.length == 8 &&
m_blue.offset == 0 &&
m_green.offset == 8 &&
m_red.offset == 16) {
qCDebug(KWIN_FB) << "Framebuffer Format is RGB888";
m_bgr = true;
m_imageFormat = QImage::Format_RGB888;
} else if (m_bitsPerPixel == 16 &&
m_red.length == 5 &&
m_green.length == 6 &&
m_blue.length == 5 &&
m_blue.offset == 0 &&
m_green.offset == 5 &&
m_red.offset == 11) {
qCDebug(KWIN_FB) << "Framebuffer Format is RGB16";
m_imageFormat = QImage::Format_RGB16;
} else {
qCWarning(KWIN_FB) << "Framebuffer format is unknown";
}
}
Outputs FramebufferBackend::outputs() const
{
return m_outputs;
}
Outputs FramebufferBackend::enabledOutputs() const
{
return m_outputs;
}
}
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
SPDX-FileCopyrightText: 2019 Roman Gilg <subdiff@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef KWIN_FB_BACKEND_H
#define KWIN_FB_BACKEND_H
#include "abstract_wayland_output.h"
#include "platform.h"
#include <QImage>
#include <QSize>
namespace KWin
{
class FramebufferBackend;
class VsyncMonitor;
class FramebufferOutput : public AbstractWaylandOutput
{
Q_OBJECT
public:
explicit FramebufferOutput(QObject *parent = nullptr);
~FramebufferOutput() override = default;
RenderLoop *renderLoop() const override;
VsyncMonitor *vsyncMonitor() const;
void init(const QSize &pixelSize, const QSize &physicalSize);
private:
void vblank(std::chrono::nanoseconds timestamp);
RenderLoop *m_renderLoop = nullptr;
VsyncMonitor *m_vsyncMonitor = nullptr;
};
class KWIN_EXPORT FramebufferBackend : public Platform
{
Q_OBJECT
Q_INTERFACES(KWin::Platform)
Q_PLUGIN_METADATA(IID "org.kde.kwin.Platform" FILE "fbdev.json")
public:
explicit FramebufferBackend(QObject *parent = nullptr);
~FramebufferBackend() override;
InputBackend *createInputBackend() override;
QPainterBackend *createQPainterBackend() override;
QSize screenSize() const override;
bool initialize() override;
Session *session() const override;
int fileDescriptor() const;
bool isValid() const {
return m_fd >= 0;
}
void map();
void unmap();
void *mappedMemory() const {
return m_memory;
}
int bytesPerLine() const {
return m_bytesPerLine;
}
int bufferSize() const {
return m_bufferLength;
}
quint32 bitsPerPixel() const {
return m_bitsPerPixel;
}
QImage::Format imageFormat() const;
/**
* @returns whether the imageFormat is BGR instead of RGB.
*/
bool isBGR() const {
return m_bgr;
}
Outputs outputs() const override;
Outputs enabledOutputs() const override;
QVector<CompositingType> supportedCompositors() const override {
return QVector<CompositingType>{QPainterCompositing};
}
private:
bool handleScreenInfo();
void initImageFormat();
QVector<FramebufferOutput*> m_outputs;
Session *m_session;
QByteArray m_id;
struct Color {
quint32 offset;
quint32 length;
};
Color m_red;
Color m_green;
Color m_blue;
Color m_alpha;
quint32 m_bitsPerPixel = 0;
int m_fd = -1;
quint32 m_bufferLength = 0;
int m_bytesPerLine = 0;
void *m_memory = nullptr;
QImage::Format m_imageFormat = QImage::Format_Invalid;
bool m_bgr = false;
};
}
#endif
{
"KPlugin": {
"Description": "Render to framebuffer.",
"Description[ar]": "التصيير إلى framebuffer",
"Description[az]": "Çərçivə tamponunun formalaşdırılması.",
"Description[ca@valencia]": "Renderitza al «framebuffer».",
"Description[ca]": "Renderitza al «framebuffer».",
"Description[da]": "Render til framebuffer.",
"Description[de]": "In Framebuffer rendern.",
"Description[el]": "Αποτύπωση σε ενδιάμεση μνήμη πλαισίων.",
"Description[en_GB]": "Render to framebuffer.",
"Description[es]": "Renderizar en el «framebuffer».",
"Description[et]": "Renderdamine kaadripuhvris.",
"Description[eu]": "Errendatu framebuffer batera.",
"Description[fi]": "Hahmonna framebufferiin.",
"Description[fr]": "Rendre sur le « framebuffer ».",
"Description[gl]": "Renderizar no búfer de fotogramas.",
"Description[hu]": "Renderelés framebufferbe.",
"Description[ia]": "Render a framebuffer.",
"Description[id]": "Render untuk framebuffer.",
"Description[it]": "Resa su framebuffer.",
"Description[ko]": "프레임버퍼에 렌더링합니다.",
"Description[lt]": "Atvaizduoti į vaizdų atnaujinimo buferį.",
"Description[nl]": "Naar framebuffer renderen.",
"Description[nn]": "Teikn opp til biletbuffer.",
"Description[pa]": "ਫਰੇਮਬਫ਼ਰ ਲਈ ਰੈਂਡਰ ਹੈ।",
"Description[pl]": "Wyświetlaj w buforze klatek.",
"Description[pt]": "Desenhar no 'framebuffer'.",
"Description[pt_BR]": "Renderizar no framebuffer.",
"Description[ro]": "Randează pe framebuffer.",
"Description[ru]": "Отрисовка во фреймбуфер",
"Description[sk]": "Renderovať do framebuffera.",
"Description[sl]": "Izriši v medpomnilnik sličic.",
"Description[sr@ijekavian]": "Рендеровање у кадробафер.",
"Description[sr@ijekavianlatin]": "Renderovanje u kadrobafer.",
"Description[sr@latin]": "Renderovanje u kadrobafer.",
"Description[sr]": "Рендеровање у кадробафер.",
"Description[sv]": "Återge i rambuffer.",
"Description[tr]": "Çerçeve tamponuna gerçekle.",
"Description[uk]": "Обробляти до буфера кадрів.",
"Description[vi]": "Kết xuất vào framebuffer.",
"Description[x-test]": "xxRender to framebuffer.xx",
"Description[zh_CN]": "渲染到帧缓冲区。",
"Description[zh_TW]": "成像至 framebuffer。",
"Id": "KWinWaylandFbdevBackend",
"Name": "framebuffer",
"Name[ar]": "framebuffer",
"Name[az]": "çərçivə tamponu",
"Name[ca@valencia]": "Framebuffer",
"Name[ca]": "Framebuffer",
"Name[cs]": "framebuffer",
"Name[da]": "framebuffer",
"Name[de]": "Framebuffer",
"Name[el]": "ενδιάμεση μνήμη πλαισίων",
"Name[en_GB]": "framebuffer",
"Name[es]": "framebuffer",
"Name[et]": "framebuffer",
"Name[eu]": "framebuffer",
"Name[fi]": "framebuffer",
"Name[fr]": "framebuffer",
"Name[gl]": "framebuffer",
"Name[hu]": "framebuffer",
"Name[ia]": "framebuffer",
"Name[id]": "framebuffer",
"Name[it]": "framebuffer",
"Name[ko]": "framebuffer",
"Name[lt]": "framebuffer",
"Name[nl]": "framebuffer",
"Name[nn]": "biletbuffer",
"Name[pa]": "ਫਰੇਮ-ਬਫ਼ਰ",
"Name[pl]": "bufor klatek",
"Name[pt]": "'Framebuffer'",
"Name[pt_BR]": "framebuffer",
"Name[ro]": "framebuffer",
"Name[ru]": "framebuffer",
"Name[sk]": "framebuffer",
"Name[sl]": "medpomnilnik sličic",
"Name[sr@ijekavian]": "Кадробафер",
"Name[sr@ijekavianlatin]": "Kadrobafer",
"Name[sr@latin]": "Kadrobafer",
"Name[sr]": "Кадробафер",
"Name[sv]": "rambuffer",
"Name[tr]": "çerçeve tampon",
"Name[uk]": "framebuffer",
"Name[vi]": "framebuffer",
"Name[x-test]": "xxframebufferxx",
"Name[zh_CN]": "framebuffer",
"Name[zh_TW]": "framebuffer"
}
}
/*
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 "logging.h"
Q_LOGGING_CATEGORY(KWIN_FB, "kwin_wayland_framebuffer", QtWarningMsg)
/*
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
*/
#ifndef KWIN_FB_LOGGING_H
#define KWIN_FB_LOGGING_H
#include <QDebug>
#include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(KWIN_FB)
#endif
/*
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 "scene_qpainter_fb_backend.h"
#include "fb_backend.h"
#include "composite.h"
#include "cursor.h"
#include "main.h"
#include "platform.h"
#include "renderloop.h"
#include "scene.h"
#include "screens.h"
#include "session.h"
#include "vsyncmonitor.h"
// Qt
#include <QPainter>
namespace KWin
{
FramebufferQPainterBackend::FramebufferQPainterBackend(FramebufferBackend *backend)
: QPainterBackend()
, m_renderBuffer(backend->screenSize(), QImage::Format_RGB32)