我們都知道,UI都是只能一個執行緒的,我的嵌入式芯片不是很強,只有一個FB,用于QT的主UI執行緒。但是我有個很關鍵的需求,就是40ms實時重繪波形不能有任何卡頓,目前波形本身繪制是不占什么資源的,就幾個點,但是其他東西在主執行緒繪制時,極大幾率都會有超過40ms的情況,甚至幾百毫秒,如果畫波形的執行緒和它們在一起,就必然要等待,效果就是一卡一卡的。有沒有什么思路方案能解決這個問題,改原始碼都可以的。雙FB合成的方案我也試過了,雖然波形不卡了,但是合成速率=刷屏速率=幀數,和解析度掛鉤,結果就是整體UI變卡了,只能放棄,有沒單UI單FB的方案?
uj5u.com熱心網友回復:
Linux系統嗎?設定執行緒優先級試過嗎?
uj5u.com熱心網友回復:
qthread 針對unix系統,無法設定執行緒優先級,在qt檔案有說明了,而且這個也不是執行緒優先級的問題,不過怎么子執行緒,最侄訓圖都必然落到主執行緒,其他東西的繪圖占用多少時間,輪到波形貼出來時就必然會等到其他東西的繪圖事件結束。我希望是比如打開一個選單,這個選單在主執行緒繪圖,卡了1秒,這1秒時間內,整個主執行緒UI都卡住等待選單的彈出,但波形要像個沒事人一樣繼續按照40ms的間隔往前繪圖行進。uj5u.com熱心網友回復:
看一下QCoreApplication::processEvents()有沒有用uj5u.com熱心網友回復:
這個應該用處不大,只要其他控制元件或者表單正在主執行緒執行著超過40ms的事情,比如某個大視窗彈出時的paintevent,那么波形的paintevent就一定會等別人干完了,才輪到他,就算你把波形優先貼,但是別人事遲早都要干的,干的程序中,干多久,波形就要等多久才輪到,除非像單片機那樣子中斷嵌套。換句話說,這個問題我覺得沒辦法從事件回圈角度去解決的。拋開代碼,總結就是只有1個執行緒,干A事和干B事,干A事每40ms就觸發一次,只干0.000001ms,迅速解決,但是干B事呢,就有可能要100ms,那么干A事就會在B事來到并且正在干的時候,必須等待它干完,才輪到A事。所以我才說這是大難題,因為QT的UI是不允許子執行緒的,估計是為了安全。畢竟只有1個framebuffer,我們知道假如2個行程同時對1framebuffer寫值,會發生什么事?那就是你的LCD屏會瘋狂閃爍。
uj5u.com熱心網友回復:
這個不是什么資料填寫和貼圖分開這些基礎問題。而是主執行緒正在被占用時并且CPU沒有100% (畢竟如果100%,就沒有討論意義了),波形要繼續貼出來,是貼出來,是能看到正在走動的貼出來。uj5u.com熱心網友回復:
又想把耗時的放ui,又想讓ui快速重繪,找到了這種框架麻煩告訴我uj5u.com熱心網友回復:
可能你沒看懂我的問題,主ui要畫界面控制元件,必然會耗時,而這個耗時的時間,是很容易超過波形的貼圖間隔,就算把除了繪圖的其他事情全放到子執行緒,但是你畫界面就都必然落到主執行緒,這個畫界面的程序,必然會把貼波形的程序卡一下,所以才希望把波形的貼圖放子執行緒。當然,我發帖只是在找做過這方面的人,沒做過這方面的人,都會覺得不可能做到,或者連題目都還沒理解。因為我們有一個成熟方案確實做到了,但是效果和解析度掛鉤,而且中間為了顯存安全不沖突,還做了些損失效率的“無用功”,導致幀數不達到預期,所以才看看有沒其他人弄過。沒弄過的人,我感覺很難會有思路的,這個甚至還有人寫了專利,思路是對的,但是寫的很上層,看了也白看。uj5u.com熱心網友回復:
基本大多數的GUI庫都是只允許由主執行緒來操作UI吧。你可以在子執行緒中去處理幀快取,主執行緒里只需要把你處理好的幀快取顯示到UI上uj5u.com熱心網友回復:
你應該是用的qPainter吧,你可以在子執行緒中使用QPainter對同一張QPixmap進行繪圖,主執行緒去繪制這張qPixmap,需要注意的就是你顯示這張pixmap的時機以及何時去清空這張pixmap,如果你不需要持續的實時繪制,你完全可以在主執行緒同時繪制這兩個圖形的pixmap,只不過如果某個pixmap如果沒有繪制完成,你只需要給這張pixmap填充透明色,子執行緒繪圖(或者重置)完畢,只需要發送一個信號,在主執行緒重繪一下界面即可uj5u.com熱心網友回復:
謝謝回答,但我好像沒看明白什么意思,是指波形區域用一個qpixmap嗎?然后子執行緒對這個pixmap繪圖。但是要眼睛看到這個pixmap,就要主執行緒真正呼叫drawpixmap把它畫出來才能看到。那假設我定時器40ms去呼叫drawpixmap,但是假如這個時候彈出一個大選單,主執行緒就會去畫這個選單,這個時候波形的drawpixmap就要等這個選單畫完并貼到螢屏上,因為它們都在一個執行緒上呀。這樣子看起來就是波形會被卡了下。我是希望波形要像單片機中斷一樣,定時時間一到,強制畫圖,強制輸出到framebuffer,眼睛必須看到波形被貼出來,效果是絲滑地、持續地走動。uj5u.com熱心網友回復:
40ms重繪的影片,幀數并不是很高,即便是你對整個螢屏進行一個實時的繪制也不會卡頓,占用都不會很高。也就是說單純進行一個圖形的繪制,沒有太多處理,實時繪制是完全可以做到的。卡頓的原因你也清楚,是因為主執行緒的阻塞導致的。假設你這個主選單對應A(pixmap),波形區域對應B,使用定時器去重繪界面,在主執行緒中只負責繪制這兩個pixmap,也就是說主界面只能接觸到這兩個pixmap(從全域來看,你只是寫了一個顯示兩張圖片的視窗,而當下的計算機性能是很輕松就能完成的),而你要繪制波形區域,則是在子執行緒中對這個pixmap進行處理,處理頻率可以由你自行設定,它不會導致主執行緒的阻塞uj5u.com熱心網友回復:
我看你之前的回答,你說A需要0.01ms,B可能100ms,所以主執行緒可能40ms完成不了繪制導致卡頓,是因為你把大多事情都交給主執行緒了(比方說一些繪圖的設定操作)你需要做的是,主執行緒40ms定時重繪,每一次重繪都去繪制兩張pixmap,不管這個pixmap里是什么。然后呢要做的就是在一個執行緒中以0.01ms去處理A對應的pixmap,以另一個執行緒以100ms來處理B對應的pixmap,這樣就能保證主執行緒同步也不會出現卡頓
uj5u.com熱心網友回復:
如果你需要更高性能的繪圖,可以學一下Qt封裝的QOpenGLWidget,不過需要3D圖形基礎,短期內很難掌握uj5u.com熱心網友回復:
這個已經有點像我最開始說的雙FB合成的方案。
我的運行平臺是嵌入式芯片,單核800MHz,linux系統,只有一個framebuffer。
首先我們知道,qt自己的控制元件,都是默認paintevent繪制內容,且在主執行緒。我們自己畫的widget確實實作了子執行緒里對pixmap畫圖,然后發給主執行緒,主執行緒paintevent直接呼叫drawpixmap。但如果要用你的方法,就要針對到所有用到的qt控制元件,qpushbutton, qwindow之類的都要自己實作雙pixmap的更新機制,但這顯然是不現實的。實際上我們的專案有很多很多選單,用了很多qt自帶的控制元件,當然也有我們自己代碼畫的qwidget控制元件。
uj5u.com熱心網友回復:
這個沒必要,因為我們波形區的波形繪圖速度很快,占用資源少,反而是QT自帶的控制元件,視窗占用比較高,是QT的UI卡了波形,不是波形卡了UI。總不可能把整個工程所有用到的qt控制元件,自己用qopenglwidget畫一遍,所有邏輯實作一遍來代替qt自己的控制元件把。。。最多就是把qt的后端從linuxfb改為eglfs,然后編譯的qt庫支持opengles,不過這個也需要芯片廠家的驅動支持。實際上有沒有這個并不會解決我說的問題,除非它能把我的UI所有繪圖,從幾十毫秒,幾百毫秒,直接壓縮到1毫秒,跟臺電腦一樣的速度,然而很可惜,這個CPU的圖形卡做不到這個程度。uj5u.com熱心網友回復:
螢屏大概有一半的區域是繪制實時波形的,40ms定時繪制打點走動。其余區域有些是熱鍵,有些是定時更新的其他引數數值矩形widget塊。點開熱鍵會彈出各個選單。熱鍵都是qpushbutton實作的,選單里面還有很多qt控制元件,combobox, spinbox啊,qlabel啊之類的。new一個空白大選單,show出來,少說主執行緒就要幾十毫秒,這個程序,假如主界面其他widget也要update,那么波形看起來更加是一頓一頓的。uj5u.com熱心網友回復:
有用戶互動的時候,卡頓一下算正常吧。沒有互動的時候,你不主動去重繪界面,它不會重繪的呀。 你這個定時重繪的機制可以優化一下,改成有資料變化到時間再重繪,沒變化就不用刷。uj5u.com熱心網友回復:
