diff --git a/plugins/platforms/fbdev/fb_backend.cpp b/plugins/platforms/fbdev/fb_backend.cpp index 6e374f5f4..2dccb334f 100644 --- a/plugins/platforms/fbdev/fb_backend.cpp +++ b/plugins/platforms/fbdev/fb_backend.cpp @@ -1,270 +1,284 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2015 Martin Gräßlin 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 . *********************************************************************/ #include "fb_backend.h" #include "composite.h" #include "logging.h" #include "logind.h" #include "scene_qpainter_fb_backend.h" #include "outputscreens.h" #include "virtual_terminal.h" #include "udev.h" // system #include #include #include #include // Linux #include namespace KWin { +void FramebufferOutput::init(const QSize &size) +{ + m_pixelSize = size; + KWayland::Server::OutputDeviceInterface::Mode mode; + mode.id = 0; + mode.size = size; + mode.flags = KWayland::Server::OutputDeviceInterface::ModeFlag::Current; + mode.refreshRate = 60000; // TODO: get actual refresh rate of fb device? + AbstractWaylandOutput::initWaylandOutputDevice("model_TODO", "manufacturer_TODO", + "UUID_TODO", { mode }); +} + FramebufferBackend::FramebufferBackend(QObject *parent) : Platform(parent) { + handleOutputs(); } FramebufferBackend::~FramebufferBackend() { unmap(); if (m_fd >= 0) { close(m_fd); } } Screens *FramebufferBackend::createScreens(QObject *parent) { return new OutputScreens(this, parent); } QPainterBackend *FramebufferBackend::createQPainterBackend() { return new FramebufferQPainterBackend(this); } void FramebufferBackend::init() { setSoftWareCursor(true); LogindIntegration *logind = LogindIntegration::self(); auto takeControl = [logind, this]() { if (logind->hasSessionControl()) { openFrameBuffer(); } else { logind->takeControl(); connect(logind, &LogindIntegration::hasSessionControlChanged, this, &FramebufferBackend::openFrameBuffer); } }; if (logind->isConnected()) { takeControl(); } else { connect(logind, &LogindIntegration::connectedChanged, this, takeControl); } VirtualTerminal::create(this); } void FramebufferBackend::openFrameBuffer() { VirtualTerminal::self()->init(); QString framebufferDevice = deviceIdentifier().constData(); if (framebufferDevice.isEmpty()) { framebufferDevice = QString(Udev().primaryFramebuffer()->devNode()); } int fd = LogindIntegration::self()->takeDevice(framebufferDevice.toUtf8().constData()); qCDebug(KWIN_FB) << "Using frame buffer device:" << framebufferDevice; if (fd < 0) { qCWarning(KWIN_FB) << "Failed to open frame buffer device:" << framebufferDevice << "through logind, trying without"; } fd = open(framebufferDevice.toUtf8().constData(), O_RDWR | O_CLOEXEC); if (fd < 0) { qCWarning(KWIN_FB) << "failed to open frame buffer device:" << framebufferDevice; emit initFailed(); return; } m_fd = fd; if (!handleScreenInfo()) { qCWarning(KWIN_FB) << "failed to handle framebuffer information"; emit initFailed(); return; } initImageFormat(); if (m_imageFormat == QImage::Format_Invalid) { emit initFailed(); return; } setReady(true); emit screensQueried(); } 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(this); - output->setPixelSize(QSize(varinfo.xres, varinfo.yres)); + output->init(QSize(varinfo.xres, varinfo.yres)); output->setRawPhysicalSize(QSize(varinfo.width, varinfo.height)); + output->setEnabled(true); m_outputs << 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; } } diff --git a/plugins/platforms/fbdev/fb_backend.h b/plugins/platforms/fbdev/fb_backend.h index 09bf37ff2..c38e29ca0 100644 --- a/plugins/platforms/fbdev/fb_backend.h +++ b/plugins/platforms/fbdev/fb_backend.h @@ -1,131 +1,129 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright 2015 Martin Gräßlin Copyright 2019 Roman Gilg 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 . *********************************************************************/ #ifndef KWIN_FB_BACKEND_H #define KWIN_FB_BACKEND_H #include "abstract_wayland_output.h" #include "platform.h" #include #include namespace KWin { class FramebufferOutput : public AbstractWaylandOutput { Q_OBJECT public: FramebufferOutput(QObject *parent = nullptr) : AbstractWaylandOutput(parent) {} ~FramebufferOutput() override = default; + void init(const QSize &size); QSize pixelSize() const override { return m_pixelSize; } - void setPixelSize(const QSize &set) { - m_pixelSize = set; - } void setRawPhysicalSize(const QSize &set) { AbstractWaylandOutput::setRawPhysicalSize(set); } private: QSize m_pixelSize; }; 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; Screens *createScreens(QObject *parent = nullptr) override; QPainterBackend *createQPainterBackend() override; QSize screenSize() const override; void init() override; 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 supportedCompositors() const override { return QVector{QPainterCompositing}; } private: void openFrameBuffer(); bool handleScreenInfo(); void initImageFormat(); QVector m_outputs; 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