Tünaydın Projedeyiz
Qt, yalnızca grafik bileşenleri değil aynı zamanda QtNetwork, veritabanlarıyla çalışmaya yönelik bir dizi sınıf, Otomasyon için Qt (IoT uygulaması dahil) ve çok daha fazlasını içeren platformlar arası bir çerçevedir. Qt ekibi, Qt'nin gömülü sistemlerde kullanılması konusunda proaktif davrandığından kütüphaneler oldukça yapılandırılabilir. Ancak yakın zamana kadar çok az kişi Qt'yi mikrodenetleyicilere taşımayı düşündü, bunun nedeni muhtemelen böyle bir görevin zor görünmesiydi - Qt büyük, MCU'lar küçük.
Öte yandan şu anda multimedya ile çalışacak şekilde tasarlanmış ve ilk Pentium'lardan daha üstün mikrodenetleyiciler var. Yaklaşık bir yıl önce Qt blogu ortaya çıktı
Qt 4.8 uzun süredir Embox'a taşındı, bu yüzden denemeye karar verdik. Esnek animasyonun bir örneği olan moveblocks uygulamasını seçtik.
QEMU'da Qt hareket blokları
Başlangıç olarak, mümkünse Qt'yi animasyonu desteklemek için gereken minimum bileşen seti ile yapılandırıyoruz. Bunun için “-qconfig minimal,small,medium...” seçeneği var. Qt'deki bir yapılandırma dosyasını birçok makroyla (neyin etkinleştirileceği / neyin devre dışı bırakılacağı) bağlar. Bu seçenekten sonra eğer başka bir şeyi devre dışı bırakmak istiyorsak konfigürasyona başka flaglar da ekliyoruz. İşte bizim bir örneğimiz
Qt'nin çalışması için bir işletim sistemi uyumluluk katmanı eklemeniz gerekir. Bunun bir yolu QPA'yı (Qt Platform Soyutlaması) uygulamaktır. Linux için QPA'nın çalıştığı, Qt'de bulunan hazır fb_base eklentisini temel aldık. Sonuç, emboxfb adı verilen, Qt'ye Embox'ın çerçeve arabelleğini sağlayan küçük bir eklentidir ve daha sonra herhangi bir dış yardım olmadan oraya çizim yapar.
Bir eklenti oluşturmak böyle görünür
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();
}
Ve yeniden çizim böyle görünecek
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;
}
Sonuç olarak, -Os bellek boyutu için derleyici optimizasyonu etkinleştirildiğinde, kitaplık görüntüsünün 3.5 MB olduğu ortaya çıktı ve bu elbette STM32F746'nın ana belleğine sığmıyor. OpenCV ile ilgili diğer yazımızda da yazdığımız gibi bu kurulda şunlar bulunmaktadır:
- 1MB ROM
- 320 KB RAM
- 8MBSDRAM
- 16 MB QSPI
QSPI'dan kod yürütme desteği OpenCV'ye zaten eklendiğinden, Embox c Qt görüntüsünün tamamını QSPI'ye yükleyerek başlamaya karar verdik. Ve yaşasın, her şey neredeyse anında QSPI'den başladı! Ancak OpenCV örneğinde olduğu gibi çok yavaş çalıştığı ortaya çıktı.
Bu nedenle bunu bu şekilde yapmaya karar verdik - önce görüntüyü QSPI'ye kopyalıyoruz, ardından SDRAM'a yüklüyoruz ve oradan çalıştırıyoruz. SDRAM'den biraz daha hızlı hale geldi, ancak yine de QEMU'dan uzak.
Daha sonra, kayan nokta ekleme fikri ortaya çıktı; sonuçta Qt, animasyonda karelerin koordinatlarına ilişkin bazı hesaplamalar yapıyor. Denedik ama burada gözle görülür bir hızlanma elde edemedik.
En etkili fikir çerçeve arabelleğini SDRAM'den dahili belleğe taşımaktı. Bunun için ekran boyutlarını 480x272 değil 272x272 yaptık. Ayrıca renk derinliğini A8R8G8B8'den R5G6B5'e düşürdük, böylece bir pikselin boyutunu 4 bayttan 2 bayta düşürdük. Ortaya çıkan çerçeve arabelleği boyutu 272 * 272 * 2 = 147968 bayttır. Bu önemli bir hızlanma sağladı, belki de en dikkat çekici olanı animasyonun neredeyse pürüzsüz hale gelmesiydi.
En son optimizasyon, Embox kodunu RAM'den ve Qt kodunu SDRAM'den çalıştırmaktı. Bunu yapmak için, önce her zamanki gibi Embox'ı Qt'ye statik olarak bağlarız, ancak kitaplığın metin, rodata, veri ve bss bölümlerini daha sonra SDRAM'a kopyalamak için QSPI'ye yerleştiririz.
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 kodunu ROM'dan çalıştırarak da gözle görülür bir hızlanma elde ettik. Sonuç olarak animasyon oldukça düzgün çıktı:
En sonunda, makaleyi hazırlarken ve farklı Embox yapılandırmalarını denerken, Qt hareket bloklarının SDRAM'deki bir çerçeve arabelleğiyle QSPI'den harika çalıştığı ve darboğazın tam olarak çerçeve arabelleğinin boyutunda olduğu ortaya çıktı! Görünüşe göre, ilk "slayt gösterisinin" üstesinden gelmek için, çerçeve arabelleğinin boyutundaki banal azalma nedeniyle 2 kat hızlanma yeterliydi. Ancak sadece Embox kodunu çeşitli hızlı hafızalara aktararak böyle bir sonuca ulaşmak mümkün değildi (hızlanma 2 değil yaklaşık 1.5 kattı).
Kendiniz nasıl deneyebilirsiniz
STM32F7-Discovery'niz varsa Qt'yi Embox altında kendiniz çalıştırabilirsiniz. Bunun nasıl yapıldığını sitemizde okuyabilirsiniz.
Sonuç
Sonuç olarak Qt!'yi başlatmayı başardık! Bize göre görevin karmaşıklığı biraz abartılıyor. Doğal olarak mikrodenetleyicilerin özelliklerini dikkate almanız ve genel olarak bilgisayar sistemlerinin mimarisini anlamanız gerekir. Optimizasyon sonuçları, bir bilgi işlem sistemindeki darboğazın işlemci değil bellek olduğu iyi bilinen bir gerçeğe işaret etmektedir.
Bu yıl festivale katılacağız
Kaynak: habr.com