下FLTK 1.4升級(jí):從XWayland到原生Wayland實(shí)踐指南)
去年年底接了塊 STM32MP157 的板子做一個(gè)帶觸摸屏的工業(yè) HMI。GUI 選的 FLTK原因是整個(gè)畫面不復(fù)雜Qt 那一整套動(dòng)態(tài)庫(kù)放上去有點(diǎn)浪費(fèi)而 FLTK 編譯出來(lái)干干凈凈控件繪制在嵌入式場(chǎng)景下又足夠利索。板子跑的是 OpenSTLinux系統(tǒng)起來(lái)之后界面確實(shí)能出但總感覺哪里不對(duì)勁。后來(lái)扒了一下系統(tǒng)里 FLTK 的版本發(fā)現(xiàn)是 1.3.x而 OpenSTLinux 的顯示環(huán)境默認(rèn)是 Weston/Wayland1.3 自己是沒法直接上 Wayland 的。說(shuō)白了應(yīng)用是在 XWayland 上轉(zhuǎn)了一層才畫出來(lái)的。這事剛開始還能忍等我開始高頻切換頁(yè)面、做動(dòng)畫縮放的時(shí)候幀率明顯往下掉。最后我下決心把 FLTK 升到 1.4.x不但在源碼層面重新交叉編譯了一遍還把它接回了 OpenSTLinux 的 Yocto 構(gòu)建體系讓下一次燒錄系統(tǒng)時(shí)不再是臨時(shí)手動(dòng)補(bǔ)丁。這篇把整個(gè)更新過(guò)程、里面涉及的選擇邏輯、以及我踩過(guò)的坑寫出來(lái)給同樣在 OpenSTLinux 上做 FLTK 應(yīng)用開發(fā)的朋友一個(gè)參考。無(wú)論你是第一次接觸這套環(huán)境還是已經(jīng)跑過(guò)幾個(gè) Demo這篇應(yīng)該都能幫你少走一點(diǎn)彎路。1. 這次更新到底想解決什么自帶 FLTK 1.3 在 OpenSTLinux 上的憋屈1.1 OpenSTLinux 的顯示棧和 FLTK 的尷尬處境OpenSTLinux 是 ST 基于 Yocto 做的嵌入式 Linux 發(fā)行版主要面向 STM32MP1 系列微處理器。默認(rèn)的圖形棧是 Weston也就是 Wayland 合成器。這一點(diǎn)很關(guān)鍵你在板子上看到的桌面、窗口列表、觸摸事件本質(zhì)上都是 Weston 在管理。而 FLTK 1.3.x 是在 Wayland 還沒成氣候的時(shí)候定型的它的原生后端是 X11。所以在 OpenSTLinux 默認(rèn)環(huán)境下運(yùn)行 FLTK 應(yīng)用常見路徑是FLTK 應(yīng)用 → X11 庫(kù) → XWayland → Weston → DRM/KMS → LCD 屏。這一層 XWayland 轉(zhuǎn)譯并不是免費(fèi)的。每一次控件的重繪、每一次觸摸事件的上報(bào)都要在 X11 協(xié)議和 Wayland 協(xié)議之間做轉(zhuǎn)換。靜態(tài)界面看不出什么問題一旦動(dòng)畫多起來(lái)CPU 占用和幀率表現(xiàn)都很難看。1.2 升級(jí)到 FLTK 1.4 之后到底能拿到什么FLTK 1.4 最重要的變化就是提供了原生 Wayland 后端。應(yīng)用可以不再借道 XWayland而是直接和 Weston 通信走 Wayland 協(xié)議的 buffer 提交、直接渲染。資源占用和繪制延遲都是實(shí)打?qū)嵉母纳啤3?Wayland 后端1.4 還帶來(lái)了高 DPI 支持、對(duì) Cairo 和 Pango 的更好集成、以及一套統(tǒng)一的Fl_Wayland_Window_Driver之類的內(nèi)部驅(qū)動(dòng)架構(gòu)。對(duì)于一個(gè) 7 寸、10 寸這種小尺寸但分辨率很高的工業(yè)屏來(lái)說(shuō)高 DPI 支持尤其有用。以前的 1.3 版本在 1080p 的屏上如果系統(tǒng)默認(rèn)縮放不是 1字體和控件經(jīng)常會(huì)發(fā)虛要么就得自己在應(yīng)用里把所有坐標(biāo)人工縮放極其痛苦。提示如果你現(xiàn)在的應(yīng)用還在用 FLTK 1.3 并且沒有改動(dòng)計(jì)劃那先別急著升。FLTK 1.4 的個(gè)別 API 做了清理比如Fl::set_color相關(guān)的一些舊接口要留意。升級(jí)前先翻一遍官方 CHANGES 文件重點(diǎn)看1.4.0的 API 變化列表。2. 動(dòng)手前先摸底顯示鏈路、SDK 和當(dāng)前 FLTK 安裝狀態(tài)2.1 板子上先把現(xiàn)狀看清楚我拿到板子第一件事是確認(rèn)當(dāng)前系統(tǒng)里實(shí)際跑的是哪套東西。不要憑印象猜版本因?yàn)?OpenSTLinux 不同的小版本也可能帶不同的組件。先把這幾條命令都跑一遍uname -a cat /etc/os-release weston --version ls /usr/lib/libfltk* /usr/lib/*/libfltk* 2/dev/null fltk-config --version 2/dev/null || echo no fltk-config in PATH我當(dāng)時(shí)看到的輸出是 FLTK 1.3.5weston 8.0.x系統(tǒng)里沒有獨(dú)立的fltk-config庫(kù)文件直接躺在/usr/lib下。fltk-config都沒有說(shuō)明這個(gè)包是用 Yocto 配方裝的但配方的打包方式比較裸沒把配置文件導(dǎo)出到 PATH 里。這也是后面要重新整理配方的理由之一。除了版本還要搞清楚當(dāng)前顯示通道。STM32MP1 的顯示接口有 RGB、DSI、LVDS 等幾種但不管哪種在 Linux 側(cè)最后都落在 DRM/KMS 上。直接看內(nèi)核日志和 Weston 啟動(dòng)參數(shù)dmesg | grep -i drm cat /proc/cmdline ps -ef | grep westonweston進(jìn)程的啟動(dòng)參數(shù)里一般會(huì)帶--backenddrm-backend.so或類似的東西。drm-backend意味著 Weston 直接管理顯示設(shè)備這是最干凈的路徑。如果你看到--backendx11-backend.so那就說(shuō)明 Weston 自己還在 X11 上跑這個(gè)更新意義就大打折扣得先解決 Weston 的啟動(dòng)配置。2.2 交叉編譯 SDK 是不是已經(jīng)就位OpenSTLinux 的 SDK 和環(huán)境變量是分開的。如果你是第一次用找不到環(huán)境文件很正常我一開始也是到處翻find /opt -name environment-setup* 2/dev/null找到后手動(dòng) source 一下source /opt/ST/stm32mp1/4.1.0/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabisource 完以后一定要驗(yàn)證別省這一步echo $CC echo $CXX echo $SDKTARGETSYSROOT環(huán)境變量正常CC應(yīng)該指向形如arm-ostl-linux-gnueabi-gcc的交叉編譯器SDKTARGETSYSROOT指向 SDK 的 sysroot 目錄。這個(gè) sysroot 就是目標(biāo)板文件系統(tǒng)的根編譯出來(lái)的動(dòng)態(tài)庫(kù)、配置文件最終都該往里放。2.3 確認(rèn) Wayland 相關(guān)開發(fā)包是否在 sysroot 里FLTK 1.4 編譯 Wayland 后端時(shí)需要wayland-client、wayland-protocols、libdecor這些開發(fā)庫(kù)。OpenSTLinux 的 SDK 一般會(huì)帶 Wayland 協(xié)議頭文件但libdecor不一定帶。先查$ pkg-config --exists wayland-client echo yes || echo no $ pkg-config --exists libdecor-0 echo yes || echo no如果libdecor沒有編譯 FLTK 時(shí)不強(qiáng)制但窗口標(biāo)題欄和邊框就出不來(lái)。嵌入式工業(yè) HMI 一般都會(huì)去掉系統(tǒng)裝飾所以哪怕沒有也能跑。不過(guò)我建議還是把libdecor裝上否則以后想在窗口上加個(gè)關(guān)閉按鈕都麻煩。注意用 SD 卡系統(tǒng)直接在板子上編譯并不推薦。STM32MP157 的 Cortex-A7 跑編譯也能過(guò)但一次完整編譯要二三十分鐘起而且板上的空間和散熱都是問題。交叉編譯是更合理的選擇。3. 用 ST SDK 從源碼交叉編譯 FLTK 1.4 的完整路子3.1 為什么優(yōu)先用 SDK 自帶的環(huán)境而不是手寫工具鏈文件OpenSTLinux SDK 除了設(shè)置CC、CXX之外還有個(gè)容易被忽略的點(diǎn)它把pkg-config的搜索路徑、sysroot 的鏈接參數(shù)、目標(biāo) CPU 架構(gòu)的浮點(diǎn)優(yōu)化都配好了。如果繞過(guò)這套環(huán)境自己寫 CMake 工具鏈文件很容易出現(xiàn)“編譯過(guò)了跑起來(lái)崩了”的情況尤其是 NEON 浮點(diǎn)指令集這類細(xì)節(jié)手動(dòng)配置非常容易漏。所以我建議的原則是能用source environment-setup-*就不要自己造工具鏈文件。在 ST 這套環(huán)境里直接用cmake并依賴環(huán)境變量即可不需要額外指定CMAKE_TOOLCHAIN_FILE。3.2 具體編譯命令和 CMake 開關(guān)的意義我從 GitHub releases 下載了 FLTK 1.4 的源碼包解壓后開始構(gòu)建wget https://github.com/fltk/fltk/archive/refs/tags/release-1.4.0.tar.gz tar xf release-1.4.0.tar.gz cd fltk-release-1.4.0 mkdir -p build cd build接著執(zhí)行 CMake 配置。我當(dāng)時(shí)的參數(shù)是這樣cmake ../ \ -DCMAKE_INSTALL_PREFIX${SDKTARGETSYSROOT}/usr \ -DCMAKE_BUILD_TYPERelease \ -DOPTION_USE_WAYLANDON \ -DOPTION_USE_X11OFF \ -DOPTION_USE_GLOFF \ -DOPTION_USE_CAIROON \ -DOPTION_USE_PANGOON這幾個(gè)開關(guān)不是隨便寫的逐個(gè)解釋CMAKE_INSTALL_PREFIX裝到 SDK 的 sysroot 里去。這樣交叉編譯應(yīng)用時(shí)find_package(FLTK)才能找到新版本庫(kù)。OPTION_USE_WAYLANDON打開原生 Wayland 后端。這是這次升級(jí)的核心。OPTION_USE_X11OFF因?yàn)槟繕?biāo)環(huán)境就是 Weston帶 X11 后端會(huì)讓庫(kù)變大、鏈接依賴變多。但我們也有一個(gè)項(xiàng)目要用 X11 后端那個(gè)項(xiàng)目里我單獨(dú)編了一份帶 X11 的包放在/usr/local/fltk_x11。兩塊不沖突。OPTION_USE_GLOFF默認(rèn) FLTK 1.4 如果檢測(cè)到 EGL/OpenGL ES會(huì)把 GL 窗口后端一起編進(jìn)去。STM32MP1 的 GPU 雖然支持 OpenGL ES 2.0但我做的是純 2D HMI不打算讓 GPU 參與關(guān)掉 GL 可以減少一層依賴也避免在 Weston 里額外初始化 EGL 出問題。OPTION_USE_CAIROONCairo 的 2D 繪制后端。FLTK 官方一說(shuō)數(shù)據(jù)繪制可能用到打開更穩(wěn)。OPTION_USE_PANGOONPango 負(fù)責(zé)字體布局和文本渲染。嵌入式環(huán)境里如果沒有這個(gè)中文字體的處理會(huì)各種別扭。然后編譯安裝make -j$(nproc) make installmake install之后sysroot 里的 FLTK 就是 1.4.0 了。驗(yàn)證一下${SDKTARGETSYSROOT}/usr/bin/fltk-config --version這個(gè)版本號(hào)正確說(shuō)明庫(kù)和配置腳本都已經(jīng)落到 sysroot。3.3 鏈接階段常見錯(cuò)誤和缺包裝庫(kù)的排查交叉編譯 FLTK 時(shí)最常碰到的問題是鏈接期報(bào)缺符號(hào)比如undefined reference to wl_compositor_interface這類多半是 Wayland protocol 的代碼生成文件沒找到或者是鏈接時(shí)沒有加-lwayland-client。在 OpenSTLinux SDK 里正常不會(huì)缺但如果你用了非 SDK 的pkg-config路徑就會(huì)踩。其次比較隱蔽的是libdecor。如果 sysroot 里沒有l(wèi)ibdecor-0.pcFLTK 1.4 的 CMake 會(huì)自動(dòng)禁用窗口裝飾編譯不會(huì)失敗但到了板子上你發(fā)現(xiàn)所有窗口既沒有標(biāo)題欄也無(wú)法拖動(dòng)。這不是 bug是依賴缺失。如果不需要裝飾可以忽略如果需要得先把libdecor交叉編譯好裝進(jìn) sysroot再回頭編 FLTK。還有l(wèi)ibxkbcommon。Wayland 后端處理鍵盤映射時(shí)依賴它OpenSTLinux SDK 通常已經(jīng)帶上但如果你的自定義 sysroot 比較干凈記得補(bǔ)。提示每次改完 sysroot 里的庫(kù)最好重新跑一次source environment-setup-*再執(zhí)行make clean make。這套 SDK 的pkg-config緩存有時(shí)候不夠聰明環(huán)境切來(lái)切去容易拿到舊路徑。4. 讓更新在下次燒錄后還活著把 FLTK 配方接進(jìn) Yocto4.1 為什么不建議在板子上直接 make install 了事很多人的做法是交叉編譯完把.so文件 scp 到板子上或者做個(gè) rootfs 補(bǔ)丁包。這種做法做原型驗(yàn)證沒問題但做產(chǎn)品固件就麻煩大了。下次重新燒寫官方鏡像所有改動(dòng)全部消失還得手動(dòng)再來(lái)一遍。OpenSTLinux 本身是 Yocto 發(fā)行版正規(guī)做法是把 FLTK 新版本做成一個(gè) recipe讓bitbake把更新固化到鏡像里。以后重新生成鏡像一燒進(jìn)去就是新版本。4.2 如何用 Custom Layer 管理 FLTK 配方如果你的 OpenSTLinux 工程里還沒有自己的層先初始化一個(gè)bitbake-layers create-layer meta-custom bitbake-layers add-layer meta-custom在meta-custom/recipes-graphics/fltk下建配方。如果工程里原本有 FLTK 的舊配方最省事的辦法是直接用devtool升級(jí)source openstlinux-environment # 進(jìn)入構(gòu)建環(huán)境 devtool modify fltkdevtool modify會(huì)把當(dāng)前配方源碼解出來(lái)然后你可以檢查VERSION和SRC_URI。如果舊版本是 FLTK 1.3.x源碼地址遷移到了 GitHub releases需要手動(dòng)更新SRC_URI https://github.com/fltk/fltk/archive/refs/tags/release-1.4.0.tar.gz PV 1.4.0如果沒有舊配方手動(dòng)寫一個(gè)fltk_1.4.0.bb也行SUMMARY Fast Light Toolkit HOMEPAGE https://www.fltk.org/ LICENSE LGPL-2.0-with-exceptions LIC_FILES_CHKSUM file://COPYING;md5xxx SRC_URI https://github.com/fltk/fltk/archive/refs/tags/release-${PV}.tar.gz SRC_URI[sha256sum] xxx S ${WORKDIR}/fltk-release-${PV} DEPENDS libdecor wayland wayland-native wayland-protocols pango fontconfig inherit cmake EXTRA_OECMAKE -DOPTION_USE_WAYLANDON -DOPTION_USE_X11OFF -DOPTION_USE_GLOFFLIC_FILE_CHKSUM的 md5 值需要你下載解壓后自己md5sum算一下。不同版本源碼里的 COPYING 文件可能變化別省略這一步。寫好后執(zhí)行devtool build fltk構(gòu)建成功后再用devtool finish fltk meta-custom把改動(dòng)提交到層里最后重新生成鏡像bitbake st-image-weston燒錄新鏡像板子上就是新 FLTK。4.3 版本跳躍時(shí)最容易出的問題FLTK 1.3 到 1.4 的包名和文件布局有變化主要體現(xiàn)在fltk-config的路徑和默認(rèn)參數(shù)變了。庫(kù)文件名從libfltk.so.1.3變成了libfltk.so.1.4如果舊應(yīng)用里硬編碼了libfltk.so.1.3啟動(dòng)會(huì)直接報(bào)找不到共享庫(kù)。舊的fltk2相關(guān)兼容代碼如果應(yīng)用里引用了需要做適配。如果你的應(yīng)用是通過(guò) CMake 的find_package(FLTK)方式鏈接的那在新 sysroot 下重新編譯一次即可鏈接對(duì)象會(huì)自動(dòng)找到新版本。注意在 Yocto 里升級(jí)一個(gè)庫(kù)一定要把這個(gè)庫(kù)的 ABI 變更檢查清楚。FLTK 1.4 在 ABI 上沒有刻意完全兼容 1.3使用舊頭文件編譯出來(lái)的 .so 不要直接混用。5. 上板驗(yàn)證時(shí)容易翻車的幾個(gè)細(xì)節(jié)5.1 跑起來(lái)之后先做的三件事系統(tǒng)燒完板子起來(lái)以后先確認(rèn)環(huán)境確實(shí)生效再跑應(yīng)用。第一檢查版本fltk-config --version ldconfig -p | grep fltk第二確認(rèn) Wayland 后端被正確使用。不加任何配置時(shí)FLTK 1.4 會(huì)自己判斷是否處于 Wayland 會(huì)話里。可以打印一個(gè)帶窗口的演示程序比如官方 democd /usr/share/fltk/test ./demo如果界面正常出現(xiàn)再用weston-log或者其他調(diào)試工具看客戶端是不是走了 wayland 協(xié)議。最簡(jiǎn)單的方式是在啟動(dòng)應(yīng)用前設(shè)置環(huán)境變量export FLTK_BACKENDwayland ./your_app第三檢查觸摸。FLTK 1.4 在 Wayland 后端下觸摸事件來(lái)自wl_touch協(xié)議跟 X11 下的多點(diǎn)觸控路徑完全不同。如果觸摸沒反應(yīng)優(yōu)先查 Weston 的 libinput 配置而不是查 FLTK。5.2 X11 后端和 Wayland 后端混用時(shí)的運(yùn)行時(shí)切換FLTK 1.4 允許同一個(gè)程序里同時(shí)編入 X11 和 Wayland 兩個(gè)后端。你可以在程序啟動(dòng)時(shí)通過(guò)FLTK_BACKEND環(huán)境變量切換# 強(qiáng)制走 Wayland export FLTK_BACKENDwayland # 強(qiáng)制走 XWayland export FLTK_BACKENDx11如果你像我一樣有部分老代碼依賴 X11 特有行為這個(gè)特性在調(diào)試階段特別有用??梢韵仍趚11后端跑確認(rèn)不是應(yīng)用邏輯問題再切到wayland后端對(duì)比表現(xiàn)。需要小心的是兩邊后端對(duì)窗口坐標(biāo)、縮放、全屏的處理有細(xì)微差異。比如 X11 后端下Fl_Window::fullscreen()是直接告訴 X serverWayland 后端下則需要通過(guò)xdg_surface協(xié)議協(xié)商。同一個(gè) API表現(xiàn)并不完全一致。5.3 我碰到的幾個(gè)隱蔽問題先說(shuō)字體。FLTK 1.4 的 Wayland 后端走 Pango fontconfig 渲染文字。如果板子上的 fontconfig 沒有配置中文字體中文全部變方框。這個(gè)問題 1.3 在 X11 下不常見因?yàn)?X11 后端做了 FreeType 字體 fallback。升級(jí)后必須確認(rèn)fc-list | grep -i cjk如果輸出為空就得在鏡像里加入中文字體包比如packagegroup-fonts-truetype或手動(dòng)拷貝一個(gè)字體的.ttc文件到/usr/share/fonts再執(zhí)行fc-cache -f。再有就是libdecor的插件路徑。如果你用 Yocto 構(gòu)建時(shí)libdecor沒有作為插件安裝應(yīng)用啟動(dòng)后不報(bào)錯(cuò)但所有窗口都沒有標(biāo)題欄。解決辦法是確認(rèn)鏡像里包含libdecor的.so插件文件并在啟動(dòng)應(yīng)用前看一眼日志有沒有類似libdecor: No plugin found的提示。最后一個(gè)是 GPU 和 GL 的坑。STM32MP1 雖然帶 GPU但如果你在編譯 FLTK 時(shí)開了OPTION_USE_GLON應(yīng)用啟動(dòng)時(shí) Weston 會(huì)嘗試給客戶端分配 EGL 表面。如果格式不匹配可能出現(xiàn)黑屏或者白屏但應(yīng)用本身沒崩潰。這種問題最難排查。我后來(lái)干脆把 GL 關(guān)了純軟件渲染雖然大尺寸窗口的拖動(dòng)性能略遜一點(diǎn)但整個(gè)系統(tǒng)穩(wěn)定很多。5.4 更新完成后的一點(diǎn)實(shí)測(cè)對(duì)比我把同一套壓力測(cè)試界面反復(fù)切換頁(yè)面、實(shí)時(shí)曲線刷新、拖拽窗口跑了一遍FLTK 1.3.5 XWaylandCPU 占用最高到 68%刷新曲線時(shí)有可感知的撕裂。FLTK 1.4.0 原生 WaylandCPU 占用控制在 35% 左右界面刷新明顯流暢觸摸拖拽也沒有了之前的“粘手感”。這個(gè)結(jié)果在我的 7 寸屏和 10 寸屏上都復(fù)現(xiàn)了。最后分享一個(gè)小習(xí)慣更新 FLTK 這件事本身不復(fù)雜真正值錢的是要把整個(gè)流程固化下來(lái)。我現(xiàn)在每次接到新的嵌入式 GUI 項(xiàng)目第一件事不是寫代碼而是先確認(rèn) GUI 庫(kù)和顯示后端的關(guān)系再?zèng)Q定要不要在 Yocto 層面做升級(jí)。FLTK 在 OpenSTLinux 上的這套流程后面換到 Qt、換到模擬器環(huán)境也都能復(fù)用看清顯示鏈路準(zhǔn)備好交叉編譯環(huán)境把改動(dòng)收進(jìn) Yocto 配方然后花更多時(shí)間在實(shí)機(jī)驗(yàn)證上。希望這篇能讓你少走幾個(gè)我走過(guò)的彎路。