HMI / Qt

Gömülü Ekranda Akıcı HMI: Qt/QML Performans Mühendisliği

EGLFS, sahne grafiği disiplini ve C++17 backend ayrımı

Spikedge Mühendislik26. Juli 20268 dk okuma
Gömülü Ekranda Akıcı HMI: Qt/QML Performans Mühendisliği
oscilloscope-verified

Was wurde gelöst

Gömülü HMI'de kare düşmesinin üç tipik kökü — QML binding fırtınası, kırılmış batching ve sessiz yazılım render'ı — ölçüm imzalarıyla birlikte ele alınıyor. EGLFS/Wayland kararı, Qt Quick sahne grafiği disiplini, GUI thread'ini veri hızından yalıtan C++17 backend deseni ve dokunmatik gecikmenin osiloskop ile yüksek hızlı kamerayla ölçümü üretim perspektifinden anlatılıyor.

Dieser Artikel wurde auf Basis der Felderfahrungen und technischen Bewertungen des Spikedge-Engineering-Teams erstellt.

Gömülü bir HMI'de 60 FPS, kare başına 16,7 ms demektir; 30 Hz'lik bir endüstriyel panelde bile bütçe 33,3 ms'dir. Bu sürenin içine dokunmatik olayın işlenmesi, QML binding değerlendirmesi, sahne grafiği senkronizasyonu, GPU render ve vsync bekleme sığmak zorundadır. Geliştirme makinesinde fark edilmeyen 5 ms'lik bir JavaScript maliyeti, 1,8 GHz Cortex-A53 çekirdekli bir i.MX8M Plus üzerinde bütçenin üçte birine karşılık gelir. Deneyimimiz net: gömülü ekranda akıcılık GPU'nun gücüyle değil, üç katmandaki disiplinle belirlenir — render yolunun bilinçli seçimi, sahne grafiğinin ölçülerek yönetilmesi ve GUI thread'ini veri hızından yalıtan bir C++ backend. Bu yazıda üçünü de ölçüm yöntemleriyle birlikte ele alıyoruz.

Kare düşmesinin üç kökü

Sahada gördüğümüz takılmaların büyük bölümü üç nedenden birine iner ve her birinin ayırt edici bir ölçüm imzası vardır.

1. QML binding fırtınası. QML'in deklaratif motoru, bir property değiştiğinde ona bağlı tüm binding'leri yeniden değerlendirir. Yüksek frekanslı bir veri kaynağı — örneğin 1 kHz'te güncellenen bir telemetri değeri — doğrudan bir context property'ye yazılıyorsa, her yazma GUI thread'inde onlarca binding değerlendirmesi ve JavaScript çalıştırması tetikler. Kare bütçesi render'a hiç gelmeden JS'te tükenir. İmzası: QML Profiler'da "Binding" ve "JavaScript" satırları kare süresinin çoğunu kaplarken GPU yükü düşüktür. GPU'yu suçlamadan önce profiler açılır; bu vakaların çoğunda GPU masumdur.

2. Yanlış katmanlama. Qt Quick'in batch renderer'ı aynı materyali paylaşan geometrileri tek draw call'da birleştirmeye çalışır. clip: true, layer kullanılmadan animasyonlu opacity, opak ve yarı saydam öğelerin z-sırasında iç içe geçmesi bu birleştirmeyi kırar; draw call sayısı patlar ve mobil sınıfı GPU'larda (i.MX8M Plus'taki GC7000L gibi) fill rate zaten kıtken üstüne overdraw eklenir. İmzası: QSG_RENDERER_DEBUG=render çıktısında yüksek batch sayısı, QSG_VISUALIZE=overdraw ile ekranda üst üste boyanan kırmızı bölgeler.

3. Sessiz yazılım render'ı. Yocto imajında GPU sürücüsü eksikse ya da EGL yapılandırması hatalıysa Qt sessizce llvmpipe'a veya software backend'ine düşebilir. Uygulama çalışır, ekran gelir, ama bir CPU çekirdeği sürekli %100'dedir ve hiçbir sahne grafiği optimizasyonu işe yaramaz. Bu yüzden ilk kural: QSG_INFO=1 ile açılış logunda hangi render backend'inin ve hangi GPU'nun seçildiğini doğrulamadan performans konuşulmaz. Üretim imajında bu satırı kalıcı olarak loglamak, sahada BSP regresyonunu dakikalar içinde yakalatır.

EGLFS mi, Wayland mi?

Render yolu seçimi bir zevk meselesi değil, mimari bir karardır. EGLFS'te uygulama KMS/DRM üzerinden doğrudan ekrana render eder: kompozitör yok, ek kopya yok, en kısa gecikme yolu. Bedeli, tek bir tam ekran GUI sürecine mahkûm olmaktır. Wayland ise çok süreçli sistemlerin yoludur; Weston veya özel bir kompozitör kare başına bir kompozisyon geçişi ekler, ama atomic KMS ile donanım overlay plane'leri kullanıldığında kamera/video akışı GPU kompozisyonuna hiç uğramadan ekrana gidebilir.

Kriter EGLFS (KMS/DRM) Wayland (Weston / özel kompozitör)
Süreç modeli Tek tam ekran GUI süreci Çok süreçli, izole istemciler
Kompozisyon maliyeti Yok — doğrudan scanout Kare başına ek geçiş; donanım plane ile azaltılabilir
Ek gecikme En kısa yol Kompozitörün vsync zamanlamasına bağlı, +1 kareye kadar
Video/kamera katmanı Plane yönetimi elle, sınırlı Overlay plane ile zero-copy video pratik
Hata izolasyonu GUI çökerse ekran gider İstemci çökse de kompozitör ayakta kalır
Tipik kullanım Tek uygulamalı endüstriyel panel Küme + infotainment gibi çok uygulamalı HMI

Karar kuralımız basit: tek tam ekran Qt uygulaması varsa varsayılan EGLFS'tir; birden fazla GUI süreci, karma toolkit veya çökme izolasyonu gerekiyorsa Wayland — ama ancak overlay plane kullanımının gerçekten devrede olduğu weston-debug veya DRM state dökümüyle doğrulandıktan sonra. Her iki yolda da vsync kilidi ölçülmelidir: QSG_RENDER_TIMING=1 ile swap aralıklarının 16,7 ms etrafında toplandığı görülmeden "akıcı" denmez.

Sahne grafiği disiplini

Batch renderer'la kavga etmek yerine onun kurallarıyla çalışmak gerekir. Pratikte uyguladığımız kontrol listesi:

  • Batch'leri görselleştirin. QSG_VISUALIZE=batches ekranı batch başına ayrı renge boyar. Hedef, az sayıda büyük renk bloğudur; konfeti görüntüsü, kırılmış batching demektir.
  • Delegate'lerde clip: true kullanmayın. Her clip bir batch sınırıdır; 50 elemanlı bir ListView'de delegate başına clip, 50 ekstra draw call üretebilir. Kenar taşmasını tasarımla (maskeleme yerine boyutlandırmayla) çözmek çoğu zaman mümkündür.
  • Opacity animasyonunda bilinçli layer.enabled kararı verin. Çok çocuklu bir öğenin opaklığını animasyonlamak her çocuğu alpha pass'e iter; layer.enabled: true öğeyi tek dokuya indirir ama FBO maliyeti getirir. Hangisinin kazandığı ancak ölçümle bilinir.
  • Overdraw'u fill rate bütçesi olarak yönetin. Tam ekran arka plan üstüne tam ekran yarı saydam panel, her kare ekranı iki kez boyamaktır. QSG_VISUALIZE=overdraw bunu doğrudan gösterir.
  • Kare başına JavaScript'i sıfıra yaklaştırın. Canvas öğesi, her karede yeniden değerlendirilen binding zincirleri ve animasyon callback'leri GUI thread'inin senkronizasyon penceresini yer. Animasyonlar sahne grafiğinin kendi animatörlerine, hesap C++'a taşınır.

C++17 backend ayrımı

İlke tek cümledir: QML neyin gösterileceğini bildirir, değerin ne olduğuna C++ karar verir. İş mantığının JS'te yaşadığı her HMI, veri hızı arttığında aynı duvara çarpar. Doğru akış şudur: edinim thread'i (fieldbus, sensör, inference) veriyi kilitlenmeden bir snapshot'a yazar; GUI thread'i ekran tazeleme hızında bir tüketiciyle son snapshot'ı okur ve kare başına en fazla bir notify yayar. 1 kHz üretici, 60 Hz tüketici: saniyede 1000 sinyal yerine 60.

// Üretici gerçek zamanlı thread'de, tüketici GUI thread'inde.
struct Sample { uint32_t seq; float pressure; float rpm; };
static_assert(std::atomic<Sample>::is_always_lock_free); // C++17: RT tarafında kilit yok

class TelemetryBridge : public QObject {
    Q_OBJECT
    Q_PROPERTY(float pressure READ pressure NOTIFY frameReady)
public:
    // RT thread: sinyal yok, heap yok, kilit yok.
    void push(const Sample& s) { latest_.store(s, std::memory_order_release); }
    float pressure() const { return shown_.pressure; }
private slots:
    void onDisplayTick() { // GUI thread, ekran tazeleme hızında QTimer/QChronoTimer
        const Sample s = latest_.load(std::memory_order_acquire);
        if (s.seq != shown_.seq) { shown_ = s; emit frameReady(); }
    }
signals:
    void frameReady();
private:
    std::atomic<Sample> latest_{};
    Sample shown_{};
};

static_assert satırı süs değildir: Sample büyüyüp lock-free olmaktan çıktığında derleme kırılır ve gerçek zamanlı thread'e sessizce mutex girmesi engellenir. Bu ayrım, veri kaynağı gerçekten deterministik olduğunda daha da kritikleşir — EtherCAT döngüsünü 8 µs'den 3,8 µs'ye indirdiğimiz türden hard real-time sistemlerde GUI'nin RT thread'e geri basınç uygulaması kabul edilemez. Aynı desen görüntü tarafında da geçerlidir: HMI üzerine bindirilmiş nesne tespiti kutuları çiziliyorsa, model ve ön/son işleme edge AI pipeline katmanında yaşar; GUI thread'ine yalnızca kare başına bir sonuç seti girer.

Liste verisinde de kural aynıdır: QML tarafında JS dizilerini yeniden kurmak yerine QAbstractListModel kullanılır ve güncellemeler dataChanged ile hücre bazında bildirilir — delegate'lerin yıkılıp yeniden yaratılması, kare düşmesinin sık gözden kaçan bir kaynağıdır.

Dokunmatik gecikme ölçümü

Ölçmeden optimize edilen gecikme, genellikle yanlış aşamada optimize edilir. Parmak ile piksel arasındaki yol beş aşamadır: dokunmatik kontrolcünün tarama periyodu (60–120 Hz tipiktir, tek başına 8–16 ms), kernel/libinput teslimi, Qt olay işleme, bir sonraki kareye hizalanma (0–16,7 ms) ve panelin kendi iç gecikmesi. İyi ayarlanmış bir gömülü yığında uçtan uca 60–100 ms bandı gerçekçi bir hedeftir; her vsync kaçırma buna tam bir kare ekler.

İki yöntem kullanıyoruz. Birincisi ucuz ve uçtan ucadır: 240 fps slow-motion kamera (kare başına ~4,2 ms çözünürlük) parmağı ve ekranı aynı planda çeker; temas karesi ile ilk piksel değişimi arasındaki kare sayısı sayılır. İkincisi hassastır: dokunmatik kontrolcünün interrupt hattı osiloskobun bir kanalına, ekrana yapıştırılmış bir fotodiyot diğerine bağlanır — elektrik sinyalinden fotona geçen süre doğrudan okunur. Bu, WebRTC hattında glass-to-glass süreyi 200 ms altında doğrularken kullandığımız enstrümantasyon disiplininin aynısıdır. Yalnızca yazılım payını ayrıştırmak içinse libinput zaman damgası, QEventPoint.timestamp ve QQuickWindow::afterRendering arasındaki farklar loglanır; panel gecikmesi bu ölçümün dışında kalır, iki yöntem birlikte tabloyu tamamlar.

Akıcılık bir mimari özelliğidir

Kare düşmesi bir "his" değil, imzası olan bir ölçümdür: profiler'da JS satırları, batch görselleştirmesinde konfeti, açılış logunda yanlış backend. Çözüm de tek bir sihirli bayrak değil, katmanlı bir disiplindir — bilinçli render yolu, ölçülen sahne grafiği, veri hızından yalıtılmış GUI thread'i ve rakamla doğrulanmış dokunmatik gecikme. Mevcut bir HMI'de bu imzaların hangisinin baskın olduğunu sistematik biçimde çıkarmak, çoğu zaman haftalarca kör optimizasyondan daha ucuzdur; tam da bu yüzden gömülü sistem mimari denetimi çalışmalarımızda render yolu doğrulaması ve gecikme ölçümü standart adımlardır. Bütçe 16,7 ms'dir; nereye harcandığını bilen kazanır.

Weiter erkunden

QtQMLEGLFSHMIPerformans

Spikedge Engineering

Nutzen Sie diese Technologie in Ihrem System?

Schedule a 1:1 technical analysis with Spikedge engineers.

Architektur-Audit planen