首页 > 系统相关 >QT显示插件(LinuxFB)及其依赖的驱动(DRM/framebuffer)记录

QT显示插件(LinuxFB)及其依赖的驱动(DRM/framebuffer)记录

时间:2023-05-27 21:24:32浏览次数:62  
标签:src 插件 QT -- public platforms DRM plugins class

关键词:Framebuffer、linuxfb、DRM等等。

 

QT在Linux中支持多种显示插件,包括EGLFS、LinuxFB、DirectFB、Wayland等。可以通过--platfrom选项指定选择何种插件。比如:./analogclock --platform linuxfb。

QT支持多种显示插件,显示插件打开Linux内核fb设备,Linux内核中GPU/Display驱动将应用数据刷新到Display设备上。此处,简单记录以上过程涉及到的模块。

1. QT5中linuxfb显示插件

class QPlatformScreen作为基类派生了显示接口类:

src\plugins\platforms\android\qandroidplatformscreen.h:
class QAndroidPlatformScreen: public QObject, public QPlatformScreen, public AndroidSurfaceClient

src\plugins\platforms\cocoa\qcocoascreen.h:
class QCocoaScreen : public QPlatformScreen

src\plugins\platforms\directfb\qdirectfbscreen.h:
class QDirectFbScreen : public QPlatformScreen

src\plugins\platforms\eglfs\api\qeglfsscreen_p.h:
class Q_EGLFS_EXPORT QEglFSScreen : public QPlatformScreen

src\platformsupport\fbconvenience:
class QFbScreen : public QObject, public QPlatformScreen

src\plugins\platforms\haiku\qhaikuscreen.h:
class QHaikuScreen : public QPlatformScreen

src\plugins\platforms\ios\qiosscreen.h:
class QIOSScreen : public QObject, public QPlatformScreen

src\plugins\platforms\minimalegl\qminimaleglscreen.h:
 class QMinimalEglScreen : public QPlatformScreen

src\plugins\platforms\minimal\qminimalintegration.h:
 class QMinimalScreen : public QPlatformScreen

src\plugins\platforms\offscreen\qoffscreencommon.h:
 class QOffscreenScreen : public QPlatformScreen

src\plugins\platforms\openwfd\qopenwfdscreen.h:
 class QOpenWFDScreen : public QPlatformScreen

src\plugins\platforms\qnx\qqnxscreen.h:
 class QQnxScreen : public QObject, public QPlatformScreen

src\plugins\platforms\wasm\qwasmscreen.h:
 class QWasmScreen : public QObject, public QPlatformScreen

src\plugins\platforms\windows\qwindowsscreen.h:
 class QWindowsScreen : public QPlatformScreen

src\plugins\platforms\winrt\qwinrtscreen.h:
 class QWinRTScreen : public QPlatformScreen

src\plugins\platforms\xcb\qxcbscreen.h:
 class Q_XCB_EXPORT QXcbScreen : public QXcbObject, public QPlatformScreen

其中QFbScreen有派生了如下显示类:

src\plugins\platforms\bsdfb\qbsdfbscreen.h:
 class QBsdFbScreen : public QFbScreen

src\plugins\platforms\integrity\qintegrityfbscreen.h:
 class QIntegrityFbScreen : public QFbScreen

src\plugins\platforms\linuxfb\qlinuxfbdrmscreen.h:
 class QLinuxFbDrmScreen : public QFbScreen

src\plugins\platforms\linuxfb\qlinuxfbscreen.h:
 class QLinuxFbScreen : public QFbScreen

src\plugins\platforms\vnc\qvncscreen.h:
 class QVncScreen : public QFbScreen

通过make menuconfig进入Target packages->Graphic libraries and applications(graphic/text)->QT5配置显示插件,以及默认插件:

 编译完成后在Target Rootfs中每个插件以库的形式保存: 

/usr/lib/qt/plugins/platforms/
|-- libqeglfs.so
|-- libqlinuxfb.so
|-- libqminimal.so
|-- libqminimalegl.so
|-- libqoffscreen.so
`-- libqvnc.so

2. QLinuxFbScreen插件

class QLinuxFbScreen : public QFbScreen
{
    Q_OBJECT
public:
    QLinuxFbScreen(const QStringList &args);--参数的初始化赋值。
    ~QLinuxFbScreen();--去初始化,内存去映射以及关闭fb句柄。

    bool initialize() override;--打开fb,获取显示相关参数,映射frame buffer到用户空间,并以frame buffer映射内存为缓存穿件QImage,最后清空屏幕。

    QPixmap grabWindow(WId wid, int x, int y, int width, int height) const override;--通过QPixmap从映射QImage中获取屏幕内容。

    QRegion doRedraw() override;--通过QPainter刷新frame buffer。

private:
    QStringList mArgs;
    int mFbFd;
    int mTtyFd;

    QImage mFbScreenImage;
    int mBytesPerLine;
    int mOldTtyMode;

    struct {
        uchar *data;
        int offset, size;
    } mMmap;

    QPainter *mBlitter;
};

QLinuxFbScreen::initialize()打开fb设备,从中获取屏幕参数,映射frame buffer内存,并以此创建QImage对象,为后续doRedraw()和grabWindow()做好准备。

bool QLinuxFbScreen::initialize()
{
    QRegularExpression ttyRx(QLatin1String("tty=(.*)"));
    QRegularExpression fbRx(QLatin1String("fb=(.*)"));
    QRegularExpression mmSizeRx(QLatin1String("mmsize=(\\d+)x(\\d+)"));
    QRegularExpression sizeRx(QLatin1String("size=(\\d+)x(\\d+)"));
    QRegularExpression offsetRx(QLatin1String("offset=(\\d+)x(\\d+)"));

    QString fbDevice, ttyDevice;
    QSize userMmSize;
    QRect userGeometry;
    bool doSwitchToGraphicsMode = true;

    // Parse arguments
    for (const QString &arg : qAsConst(mArgs)) {
        QRegularExpressionMatch match;
        if (arg == QLatin1String("nographicsmodeswitch"))
            doSwitchToGraphicsMode = false;
        else if (arg.contains(mmSizeRx, &match))
            userMmSize = QSize(match.captured(1).toInt(), match.captured(2).toInt());
        else if (arg.contains(sizeRx, &match))
            userGeometry.setSize(QSize(match.captured(1).toInt(), match.captured(2).toInt()));
        else if (arg.contains(offsetRx, &match))
            userGeometry.setTopLeft(QPoint(match.captured(1).toInt(), match.captured(2).toInt()));
        else if (arg.contains(ttyRx, &match))
            ttyDevice = match.captured(1);
        else if (arg.contains(fbRx, &match))
            fbDevice = match.captured(1);
    }

    if (fbDevice.isEmpty()) {--如果没有指定fb设备,下面选择默认设备。
        fbDevice = QLatin1String("/dev/fb0");
        if (!QFile::exists(fbDevice))
            fbDevice = QLatin1String("/dev/graphics/fb0");
        if (!QFile::exists(fbDevice)) {
            qWarning("Unable to figure out framebuffer device. Specify it manually.");
            return false;
        }
    }

    // Open the device
    mFbFd = openFramebufferDevice(fbDevice);--打开fb设备。
    if (mFbFd == -1) {
        qErrnoWarning(errno, "Failed to open framebuffer %s", qPrintable(fbDevice));
        return false;
    }

    // Read the fixed and variable screen information
    fb_fix_screeninfo finfo;
    fb_var_screeninfo vinfo;
    memset(&vinfo, 0, sizeof(vinfo));
    memset(&finfo, 0, sizeof(finfo));

    if (ioctl(mFbFd, FBIOGET_FSCREENINFO, &finfo) != 0) {--获取当前fb设备的固定信息。
        qErrnoWarning(errno, "Error reading fixed information");
        return false;
    }

    if (ioctl(mFbFd, FBIOGET_VSCREENINFO, &vinfo)) {--获取当前fb设备的可变信息,包括分辨率、像素位宽等等。
        qErrnoWarning(errno, "Error reading variable information");
        return false;
    }

    mDepth = determineDepth(vinfo);--得出当前fb设备的色深。
    mBytesPerLine = finfo.line_length;--获取一行数据长度。
    QRect geometry = determineGeometry(vinfo, userGeometry);
    mGeometry = QRect(QPoint(0, 0), geometry.size());
    mFormat = determineFormat(vinfo, mDepth);
    mPhysicalSize = determinePhysicalSize(vinfo, userMmSize, geometry.size());

    // mmap the framebuffer
    mMmap.size = finfo.smem_len;--frambuffer的大小。
    uchar *data = (unsigned char *)mmap(0, mMmap.size, PROT_READ | PROT_WRITE, MAP_SHARED, mFbFd, 0);--将内核中framebuffer映射为可读写,大小为finfo.smem_len大小的一块buffer。
    if ((long)data == -1) {
        qErrnoWarning(errno, "Failed to mmap framebuffer");
        return false;
    }

    mMmap.offset = geometry.y() * mBytesPerLine + geometry.x() * mDepth / 8;--预留一帧+一行大小的数据。
    mMmap.data = data + mMmap.offset;--QImage的buffer从mMmap.offset开始。

    QFbScreen::initializeCompositor();
    mFbScreenImage = QImage(mMmap.data, geometry.width(), geometry.height(), mBytesPerLine, mFormat);--QImage类是设备无关的图像,可以进行像素及操作,也可被用作绘图设备。

    mCursor = new QFbCursor(this);

    mTtyFd = openTtyDevice(ttyDevice);
    if (mTtyFd == -1)
        qErrnoWarning(errno, "Failed to open tty");

    switchToGraphicsMode(mTtyFd, doSwitchToGraphicsMode, &mOldTtyMode);
    blankScreen(mFbFd, false);--调用FBIOBLANK。

    return true;
}

3. Linux DRM和framebuffer驱动

make linux-menuconfig中进入Device Driver->Graphics support,打开Direct Rendering Manager和DRM Support for PL111 CLCD driver:

 pl111驱动注册framebuffer设备:

pl111_amba_driver
    ->pl111_amba_probe
        ->pl111_versatile_init
            ->pl111_vexpress_clcd_init
        ->drm_fbdev_generic_setup
            ->drm_client_init
            ->drb_fbdev_client_hotplug
                ->drm_fb_helper_initial_config
                    ->__drm_fb_helper_initial_config_and_unlock
                        ->register_framebuffer

dtb配置:

    clcd@10020000 {
        compatible = "arm,pl111", "arm,primecell";
        reg = <0x10020000 0x1000>;
        interrupt-names = "combined";
        interrupts = <0 44 4>;
        clocks = <&oscclk1>, <&oscclk2>;
        clock-names = "clcdclk", "apb_pclk";
        /* 1024x768 16bpp @65MHz */
        max-memory-bandwidth = <95000000>;

        port {
            clcd_pads_ct: endpoint {
                remote-endpoint = <&dvi_bridge_in_ct>;
                arm,pl11x,tft-r0g0b0-pads = <0 8 16>;
            };
        };
    };

Linux DRM子系统属于GPU一部分,更多参考《DRM子系统》。关于Framebuffer,更多参考《Frame Buffer Library — The Linux Kernel documentation》《Mine of Information - Linux Framebuffer Drivers (vonos.net)》《Linux Framebuffer 实验》。

Linux Graphics Drivers: an Introduction (people.freedesktop.org)》中介绍了Linux显示相关驱动,包括Framebuffer、DRM、OpenGL等。

 参考文档:

Qt for Embedded Linux | Qt 5.15

标签:src,插件,QT,--,public,platforms,DRM,plugins,class
From: https://www.cnblogs.com/arnoldlu/p/17267914.html

相关文章

  • 【工具介绍】【001】如何在chrome安装油猴插件
    1.简介Tampermonkey(油猴脚本)是一款免费的浏览器扩展和最为流行的用户脚本管理器,它适用于Chrome,MicrosoftEdge,Safari,OperaNext,和Firefox。虽然有些受支持的浏览器拥有原生的用户脚本支持,但Tampermonkey(油猴脚本)将在您的用户脚本管理方面提供更多的便利。它提供了诸......
  • qt6 chart 画k线图
    实现的基本功能:1.显示k线,附赠一个close指标2.根据鼠标移动,画十字线3.跟随鼠标,显示当前k线的一个值。4.可以移动、缩放图形运行环境:qt6.5(其他环境未测试) CMakeLists文件:cmake_minimum_required(VERSION3.14)project(chart5LANGUAGESCXX)set(CMAKE_AUTOUI......
  • 重塑Windows!微软王炸更新:操作系统全面接入ChatGPT,Bing也能用插件了
    一夜之间,微软彻底重新定义了PC交互。因为这一次,它把Bing和ChatGPT插件的能力,注入到了整个Windows系统!这就是在刚刚结束的Build2023中,微软重磅推出的WindowsCopilot。有了它,想让自己的PC变得更适合工作,就只需要一个简单的动作——问:如何调整我的系统,(以便更好地)来完成工作?然后Windo......
  • Qt 中将std::cout 重定向到 qDebug
    #include<QtCore>#include<iostream>voidcustomMessageHandler(QtMsgTypetype,constQMessageLogContext&context,constQString&msg){QByteArraylocalMsg=msg.toLocal8Bit();switch(type){caseQtDebugMsg:......
  • C#]插件编程框架 MAF 开发总结
    1.什么是MAF和MEF?MEF和MEF微软官方介绍:https://learn.microsoft.com/zh-cn/dotnet/framework/mef/MEF是轻量化的插件框架,MAF是复杂的插件框架。因为MAF有进程隔离和程序域隔离可选。我需要插件进程隔离同时快速传递数据,最后选择了MAF。如果不需要真正的物理隔离还是建议使......
  • 一个小插件,将控制台的sql打印出来
     将下面的源码保存成一个.html文件,然后用浏览器打开,最后将它保存到浏览器标签里,就能方便下次打开啦: 源码如下:<!DOCTYPEhtml><htmllang="ch-zn"><head><metahttp-equiv="Content-Type"content="text/html;charset=UTF-8"><title>Myb......
  • discoDSP Vertigo for Mac(声音合成插件) v4.4S中文版
    通过加法合成发现声音设计的无限可能性,加法合成是一种通过将两个或多个音频信号相加而产生新声音的合成。VertigoAdditiveSynthesizer提供了一系列功能来增强您的创作潜力,包括256个振荡器,双滤波器和8种易于操作和修改的效果。discoDSPVertigo中文版插件功能特色我们的合成器......
  • Chrome 护眼模式 - 黑暗模式 - 夜眼(Night Eye) 插件
    Chrome地址栏里输入:chrome://extensions/打开插件商城:......
  • ps一键转漫画卡通插件Cartoon Maker Photoshop Plugin中文版
    CartoonMaker-Clone可轻松创建惊人的卡通人物肖像效果。该这款PhotoshopPlugin将使您有机会成为数字艺术家,无需特殊的Photoshop或绘图技能即可创建卡通和漫画。使用简单,只需打开您的照片,然后单击创建卡通即可,还可以点击编辑卡通脸预设来改善卡通效果。非常适合社交媒体。这款p......
  • QT编程: 编写低功耗BLE蓝牙调试助手(Android系统APP)
    由于工作需要,需要利用QT平台完成手机与ble蓝牙的通讯,所以就找了各种资料,算是初步的能够连接完成demo代码,但是依旧有些代码没有理解,比如特性那一片的代码,稍后还得研究啊(对了,这是低功耗蓝牙,不是经典蓝牙,看清楚了,当初不清楚经典蓝牙和低功耗蓝牙,浪费我一个星期,说多了都是泪,下面是代码......