比QT更高效的开源免费嵌入式linux图形GUI

@ZHangZMo

  • EGT-Ensemble Graphics Toolkit介绍
  • EGT具备非常高的图形渲染效率EGT采用了非常优秀的开源2D图形处理引擎-Cairo开源2D图形处理引擎Cairo的优势Cairo 2D图像引擎的性能Cairo 2D图像引擎的实际应用案例彩蛋 - 开源EDA软件KiCAD也在使用Cairo
  • EGT高效的秘诀还有哪些Cairo需要依赖PixmanPixman针对不同平台有优化
  • EGT vs QT5实际效果PK
  • 代码贴图

有些介绍资料直接来自豆包,仅代表个人意见和理解,不喜勿喷

EGT-Ensemble Graphics Toolkit介绍

The Ensemble Graphics Toolkit (EGT)是MIcrochip针对旗下ARM9、SAMA5处理器推出来的一款运行于嵌入式Linux的C++ GUI开发工具套件。EGT(嵌入式图形工具包)提供了现代化的图形用户界面(GUI)功能、外观样式,并在嵌入式 Linux 应用中尽可能贴近底层硬件的同时最大限度地提升性能。关键词是开源、免费商用

Ensemble Graphics Toolkit: Introduction

官方给出的EGT组件依赖框图

EGT具备非常高的图形渲染效率 EGT采用了非常优秀的开源2D图形处理引擎-Cairo

开源2D图形处理引擎Cairo的优势

Cairo 2D图像引擎的性能

Cairo 2D图像引擎的实际应用案例

彩蛋 - 开源EDA软件KiCAD也在使用Cairo

EGT高效的秘诀还有哪些

Cairo使用Pixman来加速底层像素的操作,Pixman能够提供图像的合成、alpha 通道处理、色彩空间转换等基本的像素级别的操作

Cairo需要依赖Pixman

Pixman针对不同平台有优化

Pixman针对ARM SIMD架构、带NEON或者MIPS、X86等架构,都有专门针对性的优化代码,来尽可能利用处理器硬件特性,加速像素的处理速度

EGT vs QT5实际效果PK

在Microchip SAMA5D27开发板上,跑Microchip EGT提供的潜水员例程,该例程会有潜水员的动态图片,同时也有2条鱼在界面上从左到右在游动,另外还不断有泡泡从底部冒出。同时将该例程功能移植到QT5上,然后两者在实际硬件上运行,对比CPU占用率的差异

QT vs Cairo性能大对比 视频对比 基于EGT开发的demo,全程CPU占用率在22%左右,而QT5基本都在70%以上

代码贴图

个人对QT开发不是很熟悉,欢迎提出更好的优化方案 以下是QT5

#include 
#include 
#include 
#include 
#include 
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    , fishFrame(0)
    , fish2Frame(0)
    , diverFrame(0)
    , bubblePixmap(":/images/smallbubble.png")
{
    ui->setupUi(this);

    // Load fish images and split them into 6 parts
    QPixmap fishPixmap(":/images/fish.png");
    QPixmap fish2Pixmap(":/images/fish2.png");
    QPixmap diverPixmap(":/images/diver.png");

    int frameWidth  = fishPixmap.width() /4;
    int frameHeight = fishPixmap.height()/2;

    for (int j = 0; j < 2; j++) {
        for (int i = 0; i < 4; ++i) {
            fishPixmaps.push_back(fishPixmap.copy(i * frameWidth, frameHeight * j, frameWidth, frameHeight));
        }
    }

    frameWidth  = fish2Pixmap.width() /2;
    frameHeight = fish2Pixmap.height()/3;

    for (int j = 0; j < 3; j++) {
        for (int i = 0; i < 2; ++i) {
            fish2Pixmaps.push_back(fish2Pixmap.copy(i * frameWidth, frameHeight * j, frameWidth, frameHeight));
        }
    }

    frameWidth  = diverPixmap.width();
    frameHeight = diverPixmap.height()/16;

    for (int i = 0; i < 16 i diverpixmaps.push_backdiverpixmap.copy0 frameheight i framewidth frameheight set the background image ui->backgroundLabel->setPixmap(QPixmap(":/images/water_1080.png"));
    ui->backgroundLabel->setScaledContents(true);

    // Set the initial fish images
    ui->fishLabel->setPixmap(fishPixmaps[0]);
    ui->fishLabel->setScaledContents(true);

    ui->fish2Label->setPixmap(fish2Pixmaps[0]);
    ui->fish2Label->setScaledContents(true);

    // Set the diver image
    ui->diverLabel->setPixmap(diverPixmaps[0]);
    ui->diverLabel->setScaledContents(true);

    // Create timers for moving the fish
    moveTimer = new QTimer(this);
    connect(moveTimer, &QTimer::timeout, this, &MainWindow::moveFish);
    moveTimer->start(50);

    moveTimer2 = new QTimer(this);
    connect(moveTimer2, &QTimer::timeout, this, &MainWindow::moveFish2);
    moveTimer2->start(50);

    // Create timers for animating the fish
    animateTimer = new QTimer(this);
    connect(animateTimer, &QTimer::timeout, this, &MainWindow::animateFish);
    animateTimer->start(100);

    animateTimer2 = new QTimer(this);
    connect(animateTimer2, &QTimer::timeout, this, &MainWindow::animateFish2);
    animateTimer2->start(100);

    // Create timers for animating the diver
    animateTimer3 = new QTimer(this);
    connect(animateTimer3, &QTimer::timeout, this, &MainWindow::animateDiver);
    animateTimer3->start(100);

    cpuTimer = new QTimer(this);
    connect(cpuTimer, &QTimer::timeout, this, &MainWindow::updateClock);
    cpuTimer->start(1000); // 每秒更新一次时钟

    // Create timer for creating bubbles
    bubbleTimer = new QTimer(this);
    connect(bubbleTimer, &QTimer::timeout, this, &MainWindow::createBubble);
    bubbleTimer->start(1000);

    // 显示 CPU 使用率的标签
    cpuLabel = new QLabel(this);
    cpuLabel->setGeometry(580, 5, 200, 40);
    cpuLabel->setStyleSheet("font-size: 20px; color: red;");
    cpuLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);

    cpuUsage = new CPUUsage(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::moveFish()
{
    int x = ui->fishLabel->x() + 5;
    if (x > this->width()) {
        x = -ui->fishLabel->width();
        int y = QRandomGenerator::global()->bounded(this->height() - ui->fishLabel->height());
        ui->fishLabel->move(x, y);
    } else {
        ui->fishLabel->move(x, ui->fishLabel->y());
    }
}

void MainWindow::moveFish2()
{
    int x = ui->fish2Label->x() + 5;
    if (x > this->width()) {
        x = -ui->fish2Label->width();
        int y = QRandomGenerator::global()->bounded(this->height() - ui->fish2Label->height());
        ui->fish2Label->move(x, y);
    } else {
        ui->fish2Label->move(x, ui->fish2Label->y());
    }
}

void MainWindow::animateFish()
{
    fishFrame = (fishFrame + 1) % fishPixmaps.size();
    ui->fishLabel->setPixmap(fishPixmaps[fishFrame]);
}

void MainWindow::animateFish2()
{
    fish2Frame = (fish2Frame + 1) % fish2Pixmaps.size();
    ui->fish2Label->setPixmap(fish2Pixmaps[fish2Frame]);
}

void MainWindow::animateDiver()
{
    diverFrame = (diverFrame + 1) % diverPixmaps.size();
    ui->diverLabel->setPixmap(diverPixmaps[diverFrame]);
}

void MainWindow::updateClock()
{
    cpuLabel->setText(QString("CPU Usage: %1%").arg(cpuUsage->getCPUUsage(), 0, 'f', 2));
    update();
}

void MainWindow::createBubble()
{
    int bubbleCount = QRandomGenerator::global()->bounded(1, 4); // Random number of bubbles between 1 and 5
    for (int i = 0; i < bubblecount i int x='QRandomGenerator::global()-'>bounded(this->width());
        int y = this->height();
        int size = QRandomGenerator::global()->bounded(5, 32); // Random size between 10 and 50
        int xspeed = 0;
        int yspeed = -QRandomGenerator::global()->bounded(5, 20); // Random speed between 1 and 10
        Bubble* bubble = new Bubble(bubblePixmap, xspeed, yspeed, QPoint(x, y), size, this);
        bubbles.push_back(bubble);
        bubble->show();
        if (bubble->getcount() >= 20) {
            break;
        }
    }
}

以下是EGT

/*
 * Copyright (C) 2018 Microchip Technology Inc.  All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 */
#include 
#include 
#include 
#include 
#include 
#include <egt/ui>
#include 
#include 
#include 
#include 

using namespace std;
using namespace egt;

class Bubble : public ImageLabel
{
public:
    Bubble(int xspeed, int yspeed, const Point& point) noexcept
        : ImageLabel(Image("file:smallbubble.png"), "", Rect(point, Size())),
          m_xspeed(xspeed),
          m_yspeed(yspeed)
    {
        flags().set(Widget::Flag::no_layout);
    }

    Bubble(const Bubble&) = default;
    Bubble(Bubble&&) = default;
    Bubble& operator=(const Bubble&) = default;
    Bubble& operator=(Bubble&&) = default;
    virtual ~Bubble() = default;

    bool animate()
    {
        bool visible = Rect(Point(0, 0), Application::instance().screen()->size()).intersect(box());

        if (visible)
        {
            Point to(box().point());
            to += Point(m_xspeed, m_yspeed);
            move(to);
        }

        return visible;
    }

private:

    Bubble() = delete;

    int m_xspeed;
    int m_yspeed;
};

class MainWindow : public TopWindow
{
public:
    MainWindow()
        : TopWindow(Size()),
          e1(r())
    {
        background(Image("file:water.png"));

        m_label = make_shared
原文链接:,转发请注明来源!