diff --git a/plugins/platforms/fbdev/fb_backend.cpp b/plugins/platforms/fbdev/fb_backend.cpp index fc7ed42c7..370ad43da 100644 --- a/plugins/platforms/fbdev/fb_backend.cpp +++ b/plugins/platforms/fbdev/fb_backend.cpp @@ -1,205 +1,211 @@ /******************************************************************** 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 "screens.h" #include "virtual_terminal.h" // system #include #include #include #include // Linux #include namespace KWin { FramebufferBackend::FramebufferBackend(QObject *parent) : Platform(parent) { } FramebufferBackend::~FramebufferBackend() { unmap(); if (m_fd >= 0) { close(m_fd); } } Screens *FramebufferBackend::createScreens(QObject *parent) { return new BasicScreens(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(); int fd = LogindIntegration::self()->takeDevice(deviceIdentifier().constData()); if (fd < 0) { qCWarning(KWIN_FB) << "Failed to open frame buffer device through logind, trying without"; } fd = open(deviceIdentifier().constData(), O_RDWR | O_CLOEXEC); if (fd < 0) { qCWarning(KWIN_FB) << "failed to open frame buffer device"; return; } m_fd = fd; queryScreenInfo(); + initImageFormat(); setReady(true); emit screensQueried(); } bool FramebufferBackend::queryScreenInfo() { 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; } m_resolution = QSize(varinfo.xres, varinfo.yres); m_physicalSize = QSize(varinfo.width, varinfo.height); 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; } QImage::Format FramebufferBackend::imageFormat() const +{ + return m_imageFormat; +} + +void FramebufferBackend::initImageFormat() { if (m_fd < 0) { - return QImage::Format_Invalid; + 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"; - return QImage::Format_RGB32; + m_imageFormat = QImage::Format_RGB32; } 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"; - return QImage::Format_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"; - return QImage::Format_RGB16; + m_imageFormat = QImage::Format_RGB16; } qCWarning(KWIN_FB) << "Framebuffer format is unknown"; - return QImage::Format_Invalid; } } diff --git a/plugins/platforms/fbdev/fb_backend.h b/plugins/platforms/fbdev/fb_backend.h index 7aee7eefc..e88899472 100644 --- a/plugins/platforms/fbdev/fb_backend.h +++ b/plugins/platforms/fbdev/fb_backend.h @@ -1,98 +1,107 @@ /******************************************************************** 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 . *********************************************************************/ #ifndef KWIN_FB_BACKEND_H #define KWIN_FB_BACKEND_H #include "platform.h" #include #include namespace KWin { 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); virtual ~FramebufferBackend(); Screens *createScreens(QObject *parent = nullptr) override; QPainterBackend *createQPainterBackend() override; QSize screenSize() const override { return m_resolution; } void init() override; bool isValid() const { return m_fd >= 0; } QSize size() const { return m_resolution; } QSize physicalSize() const { return m_physicalSize; } 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; + } private: void openFrameBuffer(); bool queryScreenInfo(); + void initImageFormat(); QSize m_resolution; QSize m_physicalSize; 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 diff --git a/plugins/platforms/fbdev/scene_qpainter_fb_backend.cpp b/plugins/platforms/fbdev/scene_qpainter_fb_backend.cpp index 732d5f31f..ec311586c 100644 --- a/plugins/platforms/fbdev/scene_qpainter_fb_backend.cpp +++ b/plugins/platforms/fbdev/scene_qpainter_fb_backend.cpp @@ -1,90 +1,90 @@ /******************************************************************** 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 "scene_qpainter_fb_backend.h" #include "fb_backend.h" #include "composite.h" #include "cursor.h" #include "virtual_terminal.h" // Qt #include namespace KWin { FramebufferQPainterBackend::FramebufferQPainterBackend(FramebufferBackend *backend) : QObject() , QPainterBackend() , m_renderBuffer(backend->size(), QImage::Format_RGB32) , m_backend(backend) { m_renderBuffer.fill(Qt::black); m_backend->map(); m_backBuffer = QImage((uchar*)backend->mappedMemory(), backend->bytesPerLine() / (backend->bitsPerPixel() / 8), backend->bufferSize() / backend->bytesPerLine(), backend->bytesPerLine(), backend->imageFormat()); m_backBuffer.fill(Qt::black); connect(VirtualTerminal::self(), &VirtualTerminal::activeChanged, this, [this] (bool active) { if (active) { Compositor::self()->bufferSwapComplete(); Compositor::self()->addRepaintFull(); } else { Compositor::self()->aboutToSwapBuffers(); } } ); } FramebufferQPainterBackend::~FramebufferQPainterBackend() = default; QImage *FramebufferQPainterBackend::buffer() { return &m_renderBuffer; } bool FramebufferQPainterBackend::needsFullRepaint() const { return false; } void FramebufferQPainterBackend::prepareRenderingFrame() { } void FramebufferQPainterBackend::present(int mask, const QRegion &damage) { Q_UNUSED(mask) Q_UNUSED(damage) if (!VirtualTerminal::self()->isActive()) { return; } QPainter p(&m_backBuffer); - p.drawImage(QPoint(0, 0), m_renderBuffer); + p.drawImage(QPoint(0, 0), m_backend->isBGR() ? m_renderBuffer.rgbSwapped() : m_renderBuffer); } bool FramebufferQPainterBackend::usesOverlayWindow() const { return false; } }