Добры дзень! Мы ў праекце
Qt - гэта кросплатформавы фрэймворк, які складаецца з не толькі графічныя кампаненты, але і такія рэчы як QtNetwork, набор класаў для працы з базамі дадзеных, Qt for Automation (у тым ліку, для рэалізацыі IoT) і шматлікае іншае. Распрацоўнікі каманды Qt загадзя прадугледзелі выкарыстанне Qt ва ўбудаваных сістэмах, таму бібліятэкі даволі добра канфігуруюцца. Аднак да нядаўніх часоў, мала хто задумляўся аб партаванні Qt на мікракантролеры, верагодна таму, што такая задача выглядае складанай – Qt вялікае, MCU маленькія.
З іншага боку, на дадзены момант існуюць мікракантролеры, прызначаныя для працы з мультымедыя і праўзыходныя першыя Pentium-ы. Каля года таму ў блогу Qt з'явіўся
У Embox ужо даўно партавана Qt 4.8, таму вырашылі паспрабаваць на ім. Выбралі прыкладанне moveblocks - прыклад спружыністай анімацыі.
Qt moveblocks на QEMU
Для пачатку які канфігуруецца Qt па магчымасці з мінімальным наборам кампанент, патрабаваным для падтрымкі анімацыі. Для гэтага існуе опцыя "-qconfig minimal,small,medium …". Яна падлучае канфігурацыйны файл са складу Qt c мноствам макрасаў - што ўключыць / што адключыць. Пасля гэтай опцыі дадаем у канфігурацыю іншыя сцягі, калі жадаем яшчэ нешта адключыць дадаткова. Вось прыклад нашай
Для таго, каб Qt зарабіла, трэба дадаць пласт сумяшчальнасці з АС. Адзін са спосабаў - рэалізаваць QPA (Qt Platform Abstraction). За аснову ўзялі ўжо гатовы ўбудова fb_base у складзе Qt, на базе якога працуе QPA для Лінукс. У выніку атрымаўся невялікі плягін emboxfb, які дае Qt фрэймбуфер Embox'a, а далей яно малюе туды ўжо без старонняй дапамогі.
Вось так выглядае стварэнне плагіна
QEmboxFbIntegration::QEmboxFbIntegration()
: fontDb(new QGenericUnixFontDatabase())
{
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
const char *fbPath = "/dev/fb0";
fbFd = open(fbPath, O_RDWR);
if (fbPath < 0) {
qFatal("QEmboxFbIntegration: Error open framebuffer %s", fbPath);
}
if (ioctl(fbFd, FBIOGET_FSCREENINFO, &finfo) == -1) {
qFatal("QEmboxFbIntegration: Error ioctl framebuffer %s", fbPath);
}
if (ioctl(fbFd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
qFatal("QEmboxFbIntegration: Error ioctl framebuffer %s", fbPath);
}
fbWidth = vinfo.xres;
fbHeight = vinfo.yres;
fbBytesPerLine = finfo.line_length;
fbSize = fbBytesPerLine * fbHeight;
fbFormat = vinfo.fmt;
fbData = (uint8_t *)mmap(0, fbSize, PROT_READ | PROT_WRITE,
MAP_SHARED, fbFd, 0);
if (fbData == MAP_FAILED) {
qFatal("QEmboxFbIntegration: Error mmap framebuffer %s", fbPath);
}
if (!fbData || !fbSize) {
qFatal("QEmboxFbIntegration: Wrong framebuffer: base = %p,"
"size=%d", fbData, fbSize);
}
mPrimaryScreen = new QEmboxFbScreen(fbData, fbWidth,
fbHeight, fbBytesPerLine,
emboxFbFormatToQImageFormat(fbFormat));
mPrimaryScreen->setPhysicalSize(QSize(fbWidth, fbHeight));
mScreens.append(mPrimaryScreen);
this->printFbInfo();
}
А вось дык вось будзе выглядаць перамалёўка
QRegion QEmboxFbScreen::doRedraw()
{
QVector<QRect> rects;
QRegion touched = QFbScreen::doRedraw();
DPRINTF("QEmboxFbScreen::doRedrawn");
if (!compositePainter) {
compositePainter = new QPainter(mFbScreenImage);
}
rects = touched.rects();
for (int i = 0; i < rects.size(); i++) {
compositePainter->drawImage(rects[i], *mScreenImage, rects[i]);
}
return touched;
}
У выніку з уключанай аптымізацыяй кампілятара па памеры памяці -Os выява бібліятэкі атрымаўся 3.5 Мб, што вядома не залазіць у асноўную памяць STM32F746. Як мы ўжо пісалі ў нашым іншым артыкуле пра OpenCV, на гэтай плаце маецца:
- 1 Мб ROM
- 320 Кб RAM
- 8 Мб SDRAM
- 16 Мб QSPI
Бо для OpenCV ужо была дададзеная падтрымка выканання кода з QSPI, мы вырашылі пачаць з таго, што загрузілі выяву Embox c Qt у QSPI цалкам. І ўра, усё амаль адразу ж запусцілася з QSPI! Але як і ў выпадку з OpenCV аказалася, што працуе занадта павольна.
Таму вырашылі рабіць так – спачатку які капіюецца выява ў QSPI, затым загружаны яго ў SDRAM і выконваемся адтуль. З SDRAM стала крыху хутчэй, але ўсё роўна далёка ад QEMU.
Далей была ідэя ўключыць плаваючую кропку - бо Qt робіць некаторыя вылічэнні каардынат квадратаў у анімацыі. Паспрабавалі, але тут не атрымалі бачнага паскарэння, хаця ў
Самым жа эфектыўным аказалася ідэя перанесці фрэймбуфер з SDRAM ва ўнутраную памяць. Для гэтага мы зрабілі памеры экрана не 480×272, а 272×272. Яшчэ панізілі глыбіню колеру з A8R8G8B8 да R5G6B5, такім чынам скараціўшы памер аднаго пікселя з 4 да 2 байт. Атрымалі памер фрэймбуфера 272*272*2 = 147968 байт. Гэта дало значнае паскарэнне, бадай, самае прыкметнае, анімацыя стала амаль плаўнай.
Апошняй аптымізацыяй стала выкананне кода Embox з RAM, а Qt з SDRAM. Для гэтага мы спачатку як звычайна лінкуем статычна Embox разам з Qt, але сегменты text, rodata, data і bss бібліятэкі размяшчаем у QSPI, з тым каб потым скапіяваць у SDRAM.
section (qt_text, SDRAM, QSPI)
phdr (qt_text, PT_LOAD, FLAGS(5))
section (qt_rodata, SDRAM, QSPI)
phdr (qt_rodata, PT_LOAD, FLAGS(5))
section (qt_data, SDRAM, QSPI)
phdr (qt_data, PT_LOAD, FLAGS(6))
section (qt_bss, SDRAM, QSPI)
phdr (qt_bss, PT_LOAD, FLAGS(6))
За рахунак выканання кода Embox з ROM таксама атрымалі адчувальнае паскарэнне. У выніку анімацыя атрымалася дастаткова плаўнай:
Ужо ў самым канцы, падрыхтоўваючы артыкул і спрабуючы розныя канфігурацыі Embox'a, высветлілася, што Qt moveblocks выдатна працуе і з QSPI з фрэймбуферам у SDRAM, а вузкім месцам быў менавіта памер фрэймбуфера! Відаць, каб пераадолець пачатковае "слайдшоў" хапала паскарэння ў 2 разы за кошт банальнага памяншэння памеру фрэймбуфера. А дамагчыся такога выніку пераносам толькі кода Embox у розныя хуткія памяці не атрымалася (паскарэнне атрымлівалася не ў 2, а прыкладна ў 1.5 разу).
Як паспрабаваць самому
Калі ў Вас ёсць STM32F7-Discovery, Вы можаце запусціць Qt пад Embox самі. Прачытаць як гэта робіцца можна на нашым
Заключэнне
У выніку нам удалося запусціць Qt! Складанасць задачы, на наш погляд, крыху перабольшана. Натуральна трэба ўлічваць спецыфіку мікракантролераў і ўвогуле разумець архітэктуру вылічальных сістэм. Вынікі аптымізацыі паказваюць на вядомы факт, што самае вузкае месца ў вылічальнай сістэме, гэта не працэсар, а памяць.
У гэтым годзе мы будзем удзельнічаць на фестывалі
Крыніца: habr.com