QPAとは
QPAはQt5(正確にはQt4.8)から導入された、プラットフォーム依存部(描画、ユーザー入力等)を隠蔽する仕組み。
Linuxでは.so、Windowsでは.dllの形で提供される。
xcb(X Window System), windows, directfb, linuxfb, eglfsなどのプラグインが用意されている。
普段ユーザーが意識することは無いが、Qtアプリが動作する際はいずれかのQPAプラグインが必ず使用されている。
QPAプラグインの使用方法
環境変数QT_QPA_PLATFORM
もしくは、Qtアプリケーション起動時の引数-platform
でQPAプラグインを指定することができる。
ただしここで指定するのは、プラグインのファイル名ではなくプラグインが返すキー値(例えばlibqxcb.soではxcb)であることに注意。
指定がない場合はシステムデフォルトのプラグインが使用される。
なおプラグインファイルが置いてあるパスは、QT_QPA_PLATFORM_PLUGIN_PATH
で指定できる。
QPAプラグインの作成
参考
http://qt5.jp/learn-qpa-01.html
QPlatformIntegrationPluginとQPlatformIntegrationをそれぞれ継承したクラスを作る。
QPlatformIntegrationはプラットフォーム依存部分を抽象化したクラスを返すメソッドを持っており、それらのメソッドをオーバーライドし、プラットフォームに応じたクラスを返すことでプラットフォーム依存部分を実装する。
QPlatformIntegrationPluginを継承したクラスは少なくとも以下の3メソッドをオーバーライドする必要がある。
virtual QPlatformWindow *createPlatformWindow(QWindow *window) const = 0;
virtual QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const = 0;
virtual QAbstractEventDispatcher *guiThreadEventDispatcher() const = 0;
QPlatformIntegrationPluginに記述するQ_PLUGIN_METADATAには対応するQtの"マイナーバージョン"まで指定する必要があるので要注意。
Q_PLUGIN_METADATAでインターフェイスを指定する必要がある。Qtのバージョンごとに対応するインターフェイスのバージョンは違っており、異なったバージョンのプラグインは認識されない。
(Qt5.1は5.1, Qt5.2/5.3は5.2が対応しているもよう)
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "hoge.json")
上記指定ではプラグインはQt5.1のみで動作し、それ以外(Qt5.2やQt5.0等)では認識されない。
また上で説明したプラグインを指定するキー値は上記メタデータのFILEで設定される。
{
"Keys":[ "hoge" ]
}
QPAプラグインが返すクラスについて
参考
http://qforever.wordpress.com/2012/04/10/qt-platform-abstraction-starter-guide/
QPlatformIntegrationのメソッドが返すクラスについて解説する。
(網羅はしていない)
QPlatformWindow
QPlatformWindowはQWindowから使われ、raise()/lower(), setWindowTitle(), geometry()/setGeometory()といったウィンドウに関するアクションをプラットフォームに伝える。
なおDirectFBプラグインにおいて、ウィンドウのアクションはQt5.1ではDirectFBが持っているcompositorへ通知されていたが、Qt5.2ではプラグインが自前でcompositeしているもよう。
QPlatformBackingStore
ウィンドウの描画エリアクラス。
QPaintDeviceを返すpaintDevice()を持っており、このメソッドでプラットフォーム依存のペイントデバイスを返すことで描画処理を最適化できる。
QPlatformPixmap
QPixmapのプラットフォーム依存部分を抽象化したクラス。
QPaintEngineを返すpaintEngine()を持っており、このメソッドでプラットフォーム依存のペイントエンジンを返すことで描画処理を最適化できる。
ペイントデバイスやペイントエンジンといったQtのPaint Systemについては以下を参照
http://qt-project.org/doc/qt-5/paintsystem.html
DirectFBプラグインについて
参考
http://qt-project.org/wiki/DirectFBAndQt
DirectFBプラグインではQBlittablePlatformPixmapを経由してQBlitterPaintEngineをペイントエンジンとして描画を行う。
QBlitterPaintEngineはQPaintEngineの一部(drawPixmap, fillRect)のみを実装している。
それ以外の処理についてはQBlitterPaintEngineの親クラスであるQRasterPaintEngineに移譲されている。
QBlitterPaintEngineで実装されている描画処理ではQDirectFbBlitterを経由してDirectFBのAPIが呼ばれているため、GPUアクセラレーションが期待できる。
しかしQRasterPaintEnginenに移譲された描画処理はDirectFBのSurfaceをLockして取得したメモリ領域に対して(そこから生成したQImageを介して)描画処理をおこなうため、GPUアクセラレーションは期待できない。
EglFSプラグインについて
EglFSプラグインはX11等のウィンドウシステムを使用せず、EGLを用いて直接フレームバッファへの描画を行うプラグインである。
QEGLPlatformBackingStore::paintDevice()
が返すpaint deviceはただのQImage
であり、またQPlatformIntegration::createPlatformPixmap()
のオーバーライドもないため、描画処理は全てCPUにて行われ、GPUによるパフォーマンス改善は見込めない。
MinimalEglプラグインのようにpaint deviceとしてQOpenGLContext
を返してしまうとGL関連のWidgetにて問題が発生するためだと思われる。