2011年8月31日 星期三

針對『電子紙』優化 Qt 繪圖事件

Standard
最近手上有一些電子紙的案件,指定使用 Qt 做為圖型平台。與一般裝置不一樣的地方,電子紙的更新頻率很低,平均下來每秒頂多刷新一次,相對於 LCD Panel 的每秒 60 次起跳,實在低的可憐。對於專職繪圖的 Qt 而言,要如何壓低刷新的頻率和確認畫面繪圖完成,最後再推入 Display,便是一個重要的課題。

壓低更新頻率比較單純,透過修改 Framebuffer Driver 就可以達成。此外,也必須利用 setUpdatesEnabled() 和 update() 盡量避免 Qt 連續多次的繪圖需求,合併一次送入 framebuffer,這樣可以減少 Qt 來不及畫完和畫面閃爍的問題。

到此為止只是改善顯示效果和基礎的建置,真正要完成完美的一次推送,通常需要使用電子紙驅動程式所提供的額外 API,它同意我們自己決定何時將 Framebuffer 的資料推送到紙上。

至於何時該將畫面推送至電子紙上?這時需要針對 QApplication 做一些修改,監聽和自己創造一個新的事件:

const QEvent::Type UpdateScreenEvent = (QEvent::Type)1234;
bool Application::notify(QObject *obj, QEvent *e)
{

     if (e->type() == UpdateScreenEvent) {
          if (updateScreen) {
              EPaperDriverCtrl *ctrl = (EPaperDriverCtrl*)EPaperDriverCtrl;
              ctrl->pushFBtoPanel();
              updateScreen = false;
          }
 
          return true;
      } else if (e->type() == QEvent::Paint) {
          updateScreen = true;
          QApplication::postEvent(this, new QEvent(UpdateScreenEvent));
      }

    return QApplication::notify(obj, e);
}

原理相當簡單,監聽所有的繪圖事件,然後送一個自定的畫面推送事件,推送事件會在所有繪圖事件完成後被執行。最後再利用 updateScreen 這個旗標來避免多次的推送事件,無論有多少推送要求,都只做一次的推送。

後記

Qt 的優點就不必多說,經過十多年的演進,已成為世上數一數二的圖形化系統,雖然 Nokia 在政治考量上,在未來產品中放棄了使用基於 Qt 的 Meego,但仍不滅 Qt 的威風,因為他早已深入各個大大小小嵌入式系統和桌面系統,我們常聽到的 KDE 便是使用 Qt 的產物。和多數 Open Source Solution 相比,Qt 最大的不同是採用了 C++,所以開發速度快捷,又由於長年來在嵌入式系統上的發展,也有很大的彈性和效能,此外 footprint 也相當小。