組み込みLinuxのためのQt

組み込み Linux デバイス用プラットフォームプラグイン

組み込み Linux システムでは、使用できるプラットフォームプラグインが複数あります:EGLFS, VkKhrDisplay, LinuxFB, Wayland です。これらのプラグインを利用できるかどうかは、Qt の設定方法に依存します。これらのうち、Waylandはコンポジターの存在を必要とし、X11やWindowsと同様に複数のウィンドウをサポートする完全なウィンドウシステムを提供します。他はウィンドウシステムなしで動作し、Qt アプリケーションがレンダリングと出力を完全に制御します。これらは通常、1画面につき1つのフルスクリーンQt「ウィンドウ」をサポートします。

EGLFSは多くのボードでデフォルトのプラグインです。もし適切でなければ、QT_QPA_PLATFORM 環境変数を使って別のプラグインをリクエストしてください。あるいは、迅速なテストのために、-platform コマンドライン引数を同じ構文で使用してください。

注意: Qt 5.0 以降、Qt は独自のウィンドウシステム (QWS) を実装していません。シングルプロセスで使用する場合は、Qt Platform Abstractionが優れたソリューションです。

Embedded Linux ツールチェーンを使用したクロスコンパイル用の Qt の設定の概要については、Configure an Embedded Linux Device を参照してください。

EGLFS

EGLは OpenGL とネイティブウィンドウシステム間のインターフェースです。Qt はコンテキストとサーフェスの管理に EGL を使用できますが、API にはプラットフォーム固有のものは含まれていません。ネイティブ・ウィンドウの作成は、必ずしも画面上の実際のウィンドウになるとは限りませんが、それでもプラットフォーム固有の手段で行う必要があります。これが、ボードやGPU固有のアダプテーション・コードが必要な理由です。通常、これらの適応は次のように提供されます:

  • EGLFSフック- プラットフォーム・プラグインにコンパイルされた単一のソース・ファイル。
  • EGLデバイス統合- 動的にロードされるプラグイン

EGLFSは、X11やWaylandのような実際のウィンドウシステムなしで、EGLとOpenGL ES 2.0の上でQtアプリケーションを実行するためのプラットフォームプラグインです。GPUを含む最新のEmbedded Linuxデバイスに推奨されるプラグインです。

Qt QuickとネイティブOpenGLアプリケーションに加えて、EGLFSはQWidget のようなソフトウェアレンダリングウィンドウもサポートしています。QWidget の場合、ウィジェットのコンテンツはCPUを使って画像にレンダリングされ、テクスチャにアップロードされた後、プラグインによって合成されます。

EGLFS は、最初のトップレベルウィンドウ(QWidget またはQQuickView のいずれか)を強制的にフルスクリーンにします。このウィンドウは、他のすべてのトップレベルウィジェットが合成されるルートウィジェットウィンドウにも選ばれます。例えば、ダイアログ、ポップアップメニュー、コンボボックスなどです。EGLFSでは、常に1つのネイティブ・ウィンドウと1つのEGLウィンドウ・サーフェスが存在し、これらは最初に作成されたウィジェットまたはウィンドウに属するため、この動作は必要です。このアプローチは、アプリケーションの寿命のために存在するメイン・ウィンドウがあり、他のすべてのウィジェットがトップレベルでないか、メイン・ウィンドウが表示された後に作成される場合にうまく機能します。

OpenGLベースのウィンドウにはさらに制限があります。EGLFSは、OpenGLベースのQWindowQQuickViewQOpenGLWidget のような単一のフルスクリーンGLウィンドウをサポートしています(Qt 5.3現在)。追加のOpenGLウィンドウを開いたり、そのようなウィンドウとQWidget-ベースのコンテンツを混在させたりすることはサポートされていません。

さらに、ドラッグ・アンド・ドロップのような、デスクトップ・プラットフォームやウィンドウ・システムのある環境用に設計されたAPIは、EGLFSではサポートされていません。

EGLFSが使用する環境変数

必要に応じて、eglfs 、以下の環境変数を使用して設定することができます:

環境変数説明
QT_QPA_EGLFS_INTEGRATIONコンパイル済みのフックに加えて、動的にロードされるプラグインを使用して、デバイ スまたはベンダー固有の適応を提供することも可能である。この環境変数は特定のプラグインを強制する。例えば、eglfs_kmsに設定するとKMS/DRMバックエンドを使用する。これは、静的フックやコンパイルインフックがデバイスの makespecs で指定されていない場合にのみオプションとなる。実際には、伝統的なコンパイルインフックはほとんど使われず、ほとんどすべてのバックエンドはプラグインに移行しています。デバイスのmakespecsには、オプションではありますが、EGLFS_DEVICE_INTEGRATION のエントリーがあります。ターゲット・システムに複数のプラグインが存在する場合、この環境変数の設定は避けてください。デスクトップ環境では、DISPLAY 環境変数の存在によって、KMS または X11 バックエンドが優先されます。

注意: 一部のボードでは、実際のプラグインの代わりにnone という特別な値が使用されます。これは、フレームバッファでEGLを使用するために特別な統合が必要ないことを示し、プラグインをロードする必要はありません。

QT_QPA_EGLFS_PHYSICAL_WIDTH そしてQT_QPA_EGLFS_PHYSICAL_HEIGHT物理的なスクリーンの幅と高さをミリメートル単位で指定します。Qt 6 以降、物理的な画面サイズは論理的な dpi を決定するために使用されなくなったことに注意してください。
QT_QPA_EGLFS_ROTATIONQWidget ベースのアプリケーションでソフトウェアレンダリングされたコンテンツに適用される回転を指定します。サポートされている値は180、90、-90です。この変数はQt Quickを含むOpenGLベースのウィンドウには適用されません。Qt Quickアプリケーションは、代わりにQMLシーンで変換を適用することができます。標準のeglfs マウスカーソルは、アプリケーションの種類に関係なく、常にこの値を考慮し、適切な位置と回転のポインタ画像を表示します。しかし、KMS/DRMバックエンドのハードウェアカーソルのような特殊なカーソルの実装では、回転をサポートしない場合があります。
QT_QPA_EGLFS_FORCEVSYNC設定されると、eglfs 、eglSwapBuffers()を呼び出すたびにフレームバッファデバイスにFBIO_WAITFORVSYNC 。この変数は、レガシーLinuxfbdev サブシステムに依存するバックエンドにのみ関係する。通常、デフォルトのスワップ間隔は 1 で、Qt は eglSwapBuffers() を呼び出すと vsync が処理されると仮定します。(ドライバのバグなどで)処理されない場合は、QT_QPA_EGLFS_FORCEVSYNC に 0 以外の値を設定してみてください。
QT_QPA_EGLFS_FORCE888設定すると、eglfs が新しいコンテキスト、ウィンドウ、またはオフスクリーン・サーフェスを作成するときに、赤、緑、青のカラー・チャンネル・サイズは無視されます。代わりに、プラグインはチャンネルあたり8ビットのコンフィギュレーションを要求します。これは、たとえばバンディングの影響などで理想的でないことがわかっているにもかかわらず、ピクセルあたり32ビットまたは24ビット未満の構成(たとえば、5-6-5または4-4-4)がデフォルトで選択されているデバイスで役立ちます。アプリケーションコードを変更する代わりに、この変数は24または32 bppコンフィギュレーションを強制するショートカットを提供します。

さらに、あまり一般的に使用されない以下の変数も使用可能です:

環境変数説明
QT_QPA_EGLFS_FBフレームバッファデバイスを上書きします。デフォルトは/dev/fb0 です。ほとんどの組み込みプラットフォームでは、フレームバッファはディスプレイの寸法などの設定を問い合わせるためだけに使用されるため、この変数はあまり意味がありません。しかし、特定のデバイスでは、この変数は、LinuxFBのfb パラメータと同様に、複数のディスプレイ・セットアップで使用するディスプレイを指定する機能を提供します。
QT_QPA_EGLFS_WIDTH そしてQT_QPA_EGLFS_HEIGHT画面の幅と高さをピクセル単位で指定する。eglfs 、フレームバッファデバイス/dev/fb0から寸法を決定しようとしますが、これは常に機能するとは限りません。手動でサイズを指定する必要があるかもしれません。
QT_QPA_EGLFS_DEPTHスクリーンの色深度を上書きします。フレームバッファデバイス/dev/fb0が利用できないプラットフォームや、クエリが成功しないプラットフォームでは、デフォルトの32 が使用されます。このようなデフォルトを上書きするには、この変数を使用する。

注意: この変数は、QScreen によって報告される色深度値にのみ影響する。EGL設定やOpenGLレンダリングに使用される色深度とは何の関係もない。

QT_QPA_EGLFS_SWAPINTERVALデフォルトでは、1 のスワップ間隔が要求される。この変数は、ディスプレイの垂直リフレッシュに同期することを可能にする。スワップ間隔の値を上書きするには、この変数を使用する。例えば、0を渡すとスワップのブロックが無効になり、同期なしで可能な限り高速に実行される。
QT_QPA_EGLFS_DEBUGこの変数が設定されると、いくつかのデバッグ情報がデバッグ出力に出力される。例えば、新しいコンテキストを作成する際に、入力QSurfaceFormat 、選択されたEGLコンフィギュレーションのプロパティが出力されます。Qt QuickのQSG_INFO 変数と一緒に使用すると、EGL設定に関連する問題のトラブルシューティングに役立つ情報を得ることができます。

ロギング

QT_QPA_EGLFS_DEBUG に加えて、eglfs は Qt の最新の分類されたロギングシステムもサポートしています。以下のロギングカテゴリーが利用可能です:

  • qt.qpa.egldeviceintegration - 動的にロードされるバックエンドのロギングを有効にします。どのバックエンドが使用されているかを確認するには、このカテゴリを使用します。
  • qt.qpa.input - と 入力ハンドラからのデバッグ出力を有効にします。指定した入力デバイスが認識され、オープンされたかどうかを調べるには、このカテゴリを使います。evdev libinput
  • qt.qpa.eglfs.kms - KMS/DRMバックエンドの冗長ロギングを有効にする。

configure を実行したら、必ずその出力を調べてください。これは、必要なEGLFSバックエンド、libudev、libinputが有効になっているかどうかを確認する、最も簡単で迅速な方法です。要するに、configure の出力に望ましくない「no」があれば、実行してください:

./configure -v

を実行して冗長出力をオンにし、各configureテストのコンパイラとリンカの起動を確認できるようにしてください。

注意: ヘッダやライブラリの欠落、リンカの失敗など、一見不可解なエラーに遭遇した場合、多くの場合、それは sysroot が不完全か壊れている証拠であり、Qt とは関係ありません。

例として、Raspberry Pi を Broadcom 専用のグラフィックドライバでターゲットにする場合、出力は以下のようになるはずです:

QPA backends:
EGLFS ................................ yes
EGLFS details:
  EGLFS i.Mx6 ........................ no
  EGLFS i.Mx6 Wayland ................ no
  EGLFS EGLDevice .................... no
  EGLFS GBM .......................... no
  EGLFS Mali ......................... no
  EGLFS Raspberry Pi ................. yes
  EGL on X11 ......................... no

もしそうでない場合、Raspberry Pi 固有のバックエンドがないと、たとえ Qt の他の部分がうまくコンパイルできても、グラフィックスのアクセラレーションが機能しないため、ビルドを進めることはお勧めできません。

VkKhrDisplay

EGLFSがOpenGL(ES)のみをサポートしているのに対し、VkKhrDisplayはVulkanAPIによるレンダリングをサポートする実験的なプラットフォームプラグインです。ディスプレイを列挙してレンダリングを設定するには、VK_KHR_displayファミリーの拡張機能に依存します。グラフィックススタック内のVulkan実装がこの機能をサポートすることは保証されていないことに注意してください。現在、このプラットフォームプラグインは、Raspberry Pi 4上で動作するMesaとV3DVで検証およびテストされています。

このプラットフォームプラグインはOpenGLやソフトウェアレンダリングをサポートしていません。そのため、QWidget ベースのユーザーインターフェイスを表示しようとすると失敗します。サポートされているQWindow サーフェス タイプはQSurface::VulkanSurface だけです。Qt Quick アプリケーションでは、QSG_RHI_BACKEND=vulkan を環境に設定するか、QQuickWindow またはQQuickView を作成する前の早い段階でQQuickWindow::setGraphicsApi(QSGRendererInterface::Vulkan); を呼び出すことで、Vulkan ベースのレンダリングを強制する必要があります。

このプラットフォームプラグインを使用するには、アプリケーションを-platform vkkhrdisplay で実行するか、QT_QPA_PLATFORMvkkhrdisplay に設定します。 このプラグインは、Qt が Vulkan をサポートするように設定されている場合にのみビルドされます。

高度な EGLFS スタイルの設定(JSON 設定ファイルなど)や、同じアプリケーションから複数の画面に出力することは、現在のところ実装されていません。ただし、アプリケーションは環境変数によって使用する画面を選択できます。

インデックス値を決定するには、プラグインによってデバッグ出力に出力されるログを確認してください。現在、これらのログは分類されていません(qDebug を使って出力されます)。プラグインが適切な表示とモードを選択するためには、ほとんどの場合、ログの検査が不可欠だからです。

  • QT_VK_DISPLAY_INDEX - 設定されると、与えられたインデックスのディスプレイが使われます。
  • QT_VK_MODE_INDEX - 設定されると、指定されたインデックスのモードが使用されます。
  • QT_VK_PHYSICAL_DEVICE_INDEX - 設定すると、指定されたインデックスの Vulkan 物理デバイスが使用されます。これは、embeddedではほとんどの場合関係ありません。この変数は、Qt グラフィックススタックの残りの部分でも使用されることに注意してください。

入力(キーボード、マウス、タッチ)の処理は EGLFS に似ており、evdevlibinputtslib をサポートしています。ただし、マウス・カーソルのレンダリングは実装されていません。これは、この環境にはハードウェアカーソルの概念がなく、EGLFSがOpenGLで行うのと同様に、プラットフォームプラグイン内でVulkanでカーソルをレンダリングすることは、複数の理由から問題があるためです。したがって、このプラットフォームプラグインは、現時点ではマウスベースの入力には適していません。

関連する環境変数は次のとおりです:

  • QT_QPA_DISABLE_INPUT - キーボード/マウス/タッチ入力を無効にします。
  • QT_QPA_NO_LIBINPUT - libinputが利用可能な場合でも、evdevベースの入力ハンドラを優先します。
  • QT_QPA_TSLIB - レガシーtslibライブラリの使用を要求する。

LinuxFB

このプラグインは Linux の fbdev サブシステム経由でフレームバッファに直接書き込みます。ソフトウェアレンダリングされたコンテンツのみがサポートされます。セットアップによっては、表示パフォーマンスが制限されることがあります。QSurface::RasterSurfaceこのプラットフォーム・プラグインで Qt Quick アプリケーションを使用するには、software scenegraph バックエンドを使用する必要があります。QT_QUICK_BACKEND=software を環境に設定するか、QSGRendererInterface::Software を使用してsetGraphicsApi() を呼び出します。QWidget アプリケーションやQWindow のサーフェスタイプはサポートされていますが、QOpenGLWidget のような特殊なウィジェットはサポートされていません。

Linuxカーネルではfbdevが非推奨となっているため、DRMダム・バッファのサポー トも利用可能です。これを使うには、QT_QPA_FB_DRM 環境変数をゼロ以外の値に設定する。設定すると、お使いのシステムでダムバッファがサポートされている場合、/dev/fb0 のようなレガシーフレームバッファデバイスにアクセスしなくなります。代わりに、EGLFSのeglfs_kms バックエンドと同様に、DRM APIを介してレンダリングが設定されます。出力はダブルバッファされ、ページが反転され、ソフトウェアレンダリングされたコンテンツにも適切なvsyncが提供されます。

注: ダムバッファが使用されている場合、物理的および論理的なスクリーンサイズなどのプロパティはすべて自動的に照会されるため、以下に説明するオプションはどれも適用できません。

追加設定の指定

linuxfb プラグインでは、QT_QPA_PLATFORM 環境変数または-platform コマンドラインオプションで追加設定を指定できます。たとえば、QT_QPA_PLATFORM=linuxfb:fb=/dev/fb1 は、デフォルトのfb0 の代わりにフレームバッファデバイス/dev/fb1 を使用することを指定します。複数の設定を指定するには、mをコロン(:)で区切ります。

設定説明
fb=/dev/fbNフレームバッファデバイスを指定します。マルチディスプレイの場合、この設定により異なるディスプレイでアプリケーションを実行することができます。現在のところ、1つのQtアプリケーションから複数のフレームバッファを使用する方法はありません。
size=<width>x<height画面サイズをピクセル単位で指定します。プラグインは、フレームバッファデバイスから物理的、論理的なディスプレイの寸法を問い合わせようとします。しかし、この問い合わせは必ずしも適切な結果をもたらさないかもしれない。
mmsize=<width>x<height>物理的な幅と高さをミリメートル単位で指定する。
offset=<width>x<height画面の左上隅のオフセットをピクセル単位で指定する。デフォルトの位置は(0, 0) である。
nographicsmodeswitch仮想端末をグラフィックスモード (KD_GRAPHICS) に切り替えないことを指定する。通常、グラフィックモードを有効にすると、カーソルの点滅と画面の白紙化が無効になる。しかし、このパラメータを設定すると、これら 2 つの機能もスキップされる。
tty=/dev/ttyN仮想コンソールを上書きする。nographicsmodeswitch が設定されていない場合にのみ使用される。

Qt 5.9 では、EGLFS と LinuxFB の動作は、ウィンドウのサイズ変更ポリシーに関して同期されました。これを望まない場合は、QT_QPA_FB_FORCE_FULLSCREEN 環境変数を0 に設定すると、以前の Qt バージョンの動作に戻ります。

出力の表示

1つのQtアプリケーションから1つ以上のディスプレイをターゲットにするサポートのレベルは、プラットフォームプラグインによって異なります。多くの場合、サポートはデバイスとそのグラフィックスタックに依存します。

eglfs_kms バックエンドによる EGLFS

KMS/DRM バックエンドが使用されている場合、EGLFS はQGuiApplication::screens() で利用可能なすべての画面を報告します。アプリケーションは、QWindow::setScreen ()を介して、異なるウィンドウで異なるスクリーンをターゲットにすることができます。

注意: 1つのスクリーンにつき1つのフルスクリーンウィンドウという制限は依然として適用されます。QWindow を表示させた後にスクリーンを変更することもサポートされていません。したがって、組み込みアプリケーションは、QWindow::show() を呼び出す前に、必要なQWindow::setScreen() をすべて呼び出しておく必要があります。

ある組み込みデバイスで開発を始めるとき、多くの場合、デバイスとドライバの動作や、接続されているディスプレイがその通りに動作しているかどうかを確認する必要があります。一つの簡単な方法は、hellowindowのサンプルを使うことです。-platform eglfs --multiscreen --timeout の引数で起動すると、接続された各スクリーンに回転する Qt ロゴが数秒間表示されます。

カスタム設定

KMS/DRMバックエンドはJSONファイルによるカスタム設定もサポートしています。これを有効にするには、QT_QPA_EGLFS_KMS_CONFIG 環境変数にファイル名を設定します。また、Qtリソースシステムを使って、このファイルをアプリケーションに埋め込むこともできます。

これらの設定オプションのほとんどは、バッファ管理技術(GBMまたはEGLStreams)に関係なく、すべてのKMS/DRMベースのバックエンドに適用されます。

以下に設定例を示します:

{
  "device": "/dev/dri/card1",
  "hwcursor": false,
  "pbuffers": true,
  "outputs": [
    {
      "name": "VGA1",
      "mode": "off"
    },
    {
      "name": "HDMI1",
      "mode": "1024x768"
    }
  ]
}

ここでは、指定されたデバイスを以下のように設定します:

  • ハードウェアカーソルを使用しない(OpenGL経由でマウスカーソルをレンダリングするようになる。)
  • 標準的なEGL pbufferサーフェスでQOffscreenSurface (デフォルトでは無効で、代わりにgbmサーフェスが使用されます)。
  • VGAコネクタの出力は無効で、HDMIは1024x768の解像度で有効です。

さらに、このようなコンフィギュレーションでは、libudev を介したデバイスの検索も無効になります。代わりに、指定されたデバイスが使用されます。

mode が定義されていない場合、システムの優先モードが選択される。modeoff current,preferred,skip, widthxheight, widthxheight@vrefresh、またはモデル文字列。

current を指定すると、現在の解像度と一致するモードが選択される。モード設定は、希望するモードが実際にアクティブなモードと異なる場合にのみ行われるため(環境変数QT_QPA_EGLFS_ALWAYS_SET_MODE によって強制されない限り)、この値は、現在のモードと、Qt が触れていないプレーンのコンテンツを保持するのに便利です。

skip off も同様ですが、モードを変更し、ディスプレイをオフにします。

デフォルトの動作

デフォルトでは、DRMレイヤーによって報告されたすべての画面は、1つの大きな仮想デスクトップとして扱われます。マウスカーソルの実装はこれを考慮し、期待どおりに画面を移動します。推奨されませんが、コンフィギュレーションでseparateScreensfalse に設定することで、仮想デスクトップを無効にすることができます。

デフォルトでは、仮想デスクトップはシステムから報告されたコネクタの順序に基づいて、左から右に形成されます。これを変更するには、virtualIndex を 0 から始まる値に設定します。

たとえば、次の構成では優先解像度を使用しますが、仮想デスクトップの左側がHDMIポートに接続された画面であり、右側がDisplayPortに接続された画面であることを保証します:

{
  "device": "drm-nvdc",
  "outputs": [
    {
      "name": "HDMI1",
      "virtualIndex": 0
    },
    {
      "name": "DP1",
      "virtualIndex": 1
    }
  ]
}

配列の要素の順番は関係ありません。仮想インデックスが指定されていない出力は、DRMコネクタリストの元の順序を保持したまま、他の出力の後に配置されます。

垂直のデスクトップ・スペースを作成するには(つまり、左から右ではなく、上から下へスタックするには)、device の後に、vertical の値を持つvirtualDesktopLayout プロパティを追加します。

警告 仮想デスクトップ内のすべての画面で同じ解像度を使用することをお勧めします。そうしないと、1つの画面にしか存在しない領域に入ったときに、マウス・カーソルなどの要素が予期しない動作をすることがあります。

virtualIndex では不十分な場合は、virtualPos プロパティを使用して、該当するスクリーンの左上位置を明示的に指定することができます。先ほどの例で、HDMI1の解像度を1080pと仮定すると、次のコード・スニペットは、2つ目のHDMIベースのスクリーンを1つ目のスクリーンの下に配置します:

{
   ...
  "outputs": [
    ...
    {
      "name": "HDMI2",
      "virtualPos": "0, 1080"
    }
  ]
}

注意: マウスをサポートしたい場合は、このような構成は避けてください。注:マウスサポートが必要な場合は、このような構成は避けてください。マウスカーソルの動作は、ノンリニアレイアウトでは予期しない場合があります。タッチは問題ありません。

フィジックスクリーンサイズの自動問い合わせ

DRMによる物理画面サイズの自動照会に失敗する場合があります。通常は、QT_QPA_EGLFS_PHYSICAL_WIDTHQT_QPA_EGLFS_PHYSICAL_HEIGHT 環境変数を使用して、不足する値を提供します。複数の画面が存在する場合、これはもう適切ではありません。代わりに、outputs リスト内のphysicalWidthphysicalHeight プロパティを使用して、ミリメートル単位でサイズを指定します。

注: 物理的なサイズが異なり、したがって論理的なDPIも異なることは、グラフィックスタックコンポーネントの中には、複数のスクリーンについて知らず、最初のスクリーンの値だけに依存するものがあるため、予期せぬ問題につながる可能性があるため、推奨されません。

アクティブな出力とQScreenインスタンス

outputs 配列からの各アクティブ出力は、QGuiApplication::screens ()から報告された1つのQScreen インスタンスに対応する。デフォルトでは、QGuiApplication::primaryScreen() が報告する主な画面は、最初に登録された画面です。virtualIndex を使用していない場合は、DRM コネクタの順序に基づいて決定されます。これをオーバーライドするには、outputs リスト内の目的のエントリで、primary プロパティをtrue に設定します。

例えば、システムがたまたまHDMIを最初に報告した場合でも、VGA出力に対応する画面がプライマリになるようにするには、次のようにします:

{
  "device": "/dev/dri/card0",
  "outputs": [
      { "name": "HDMI1" },
      { "name": "VGA1", "mode": "1280x720", "primary": true },
      { "name": "LVDS1", "mode": "off" }
  ]
}

トラブルシューティングのために、KMS/DRMバックエンドからのデバッグログを有効にすると便利です。これを行うには、qt.qpa.eglfs.kms カテゴリロギングルールを有効にします。

注意: 組み込み環境では、仮想デスクトップはフルウィンドウシステムに比べて制限されます。複数のスクリーンに重なるウィンドウ、フルスクリーンでないウィンドウ、スクリーン間のウィンドウの移動は避けるべきですし、期待通りに機能しないかもしれません。

一般的な使用例

マルチスクリーンのセットアップで最も一般的で、最もよくサポートされている使用例は、各スクリーン専用のQQuickWindow またはQQuickView を開くことです。Qt Quick scenegraphのデフォルトのthreaded レンダリングループでは、これらのウィンドウはそれぞれ専用のレンダリングスレッドを取得します。これは、スレッドを vsync に基づいて個別にスロットルでき、互いに干渉しないためです。basic ループでは、これが問題となり、アニメーションが劣化することがあります。

例えば、接続されているすべてのスクリーンを検出し、それらのスクリーンごとにQQuickView

int main(int argc, char **argv)
{
    QGuiApplication app(argc, argv);

    QVector<QQuickView *> views;
    for (QScreen *screen : app.screens()) {
        QQuickView *view = new QQuickView;
        view->setScreen(screen);
        view->setResizeMode(QQuickView::SizeRootObjectToView);
        view->setSource(QUrl("qrc:/main.qml"));
        QObject::connect(view->engine(), &QQmlEngine::quit, qGuiApp, &QCoreApplication::quit);
        views.append(view);
        view->showFullScreen();
    }

    int result = app.exec();

    qDeleteAll(views);
    return result;
}

eglfs_kmsの高度な機能

クローン(ミラーリング)

画面の複製(ミラーリング)がサポートされています。これはclones プロパティで有効になります:

{
  "device": "/dev/dri/card0",
  "outputs": [
      { "name": "HDMI1", "mode": "1920x1080" },
      { "name": "DP1", "mode": "1920x1080", "clones": "HDMI1" }
 ]
}

この場合、DisplayPort経由で接続されたディスプレイ上のコンテンツは、HDMI上のものと同じになります。この場合、DisplayPort経由で接続されたディスプレイ上のコンテンツは、HDMI上のものと同じになります。これは、両方で同じバッファをスキャンアウトすることで保証されます。

しかし、この機能は、解像度が同じで、受け入れられるバッファフォーマットに関して非互換性がなく、アプリケーションがクローンデスティネーションに関連付けられたQScreen 。実際には、後者は、問題のQScreen (例ではDP1)に関連するQWindow 、決してQOpenGLContext::swapBuffers ()オペレーションを実行してはならないことを意味します。これを確実にするのは、コンフィギュレーションとアプリケーション次第である。

DRMレンダーを使用したヘッドレスモード

DRMレンダー・ノードを使用したヘッドレス・モードがサポートされています。これにより、DRMマスター権限を必要とせずに、GPUコンピュート(OpenGLコンピュート・シェーダー、OpenCL)またはオフスクリーンOpenGLレンダリングを実行できます。このモードでは、画面に出力する別のプロセスがすでにある場合でも、アプリケーションを機能させることができます。

/dev/dri/card0 から/dev/dri/renderD128device を切り替えるだけでは、ヘッドレスモードでは実行できない操作が多数あるため、それだけでは無駄です。そのため、headless プロパティなどと組み合わせる必要があります:

{
    "device": "/dev/dri/renderD128",
    "headless": "1024x768"
}

そのため、headless プロパティでサイズを指定する必要があります。vsyncベースのスロットリングもありません。

有効化されると、アプリケーションは、ヘッドレスモードでオフスクリーンレンダリングを実行するために、2つの典型的な選択肢があります:

QOpenGLWindow サブクラスなどの通常のウィンドウを使用し、ウィンドウのデフォルトのフレームバッファ、つまり実際にはgbm_surface

MyOpenGLWindow w;
w.show(); // will not actually show up on screen
w.grabFramebuffer().save("output.png");

または、余分なFBOを使用した典型的なオフスクリーンアプローチ:

QOffscreenSurface s;
s.setFormat(ctx.format());
s.create();
ctx.makeCurrent(&s);
QOpenGLFramebufferObject fbo(1024, 768);
fbo.bind();
ctx.functions()->glClearColor(1, 0, 0, 1);
ctx.functions()->glClear(GL_COLOR_BUFFER_BIT);
fbo.toImage().save("output.png");
ctx.doneCurrent();

DRM APIの選択

KMS/DRMは、レガシーと アトミックの2つの異なるDRM APIで使用できます。DRMアトミックAPIの主な利点は、レガシーAPIではvsyncごとに1プレーンの更新が必要なのに対し、同じレンダリングループ内で複数のDRMプレーンの更新が可能になることです。

アトミックAPIは、アプリケーションがすべての更新を同じvsync内で維持しながら、コンテンツをオーバーレイにブレンドする必要がある場合に便利です。まだすべてのデバイスがこのAPIをサポートしているわけではなく、一部の古いデバイスでは利用できない可能性があります。KMSバックエンドはデフォルトでレガシーAPIを使用しますが、QT_QPA_EGLFS_KMS_ATOMIC 環境変数を1に設定することで、DRMアトミックAPIを有効にすることができます。

画面解像度よりも小さなフレームバッファを使用することも有効です。これは、JSONファイルのsize パラメータを使用して、DRMアトミックで可能です。以下の例では、3840x2160のビデオモードで1280x720のフレームバッファを使用しています:

{
  "device": "/dev/dri/card0",
  "outputs": [
    { "name": "HDMI1", "mode": "3840x2160", "size": "1280x720", "format": "argb8888" }
  ]
}

eglfs_kms_egldeviceバックエンドを使用したEGLFS

このバックエンドは通常 Tegra デバイスで使用され、GBM の代わりに EGLDevice と EGLStream 拡張に依存する点を除けば、前述の KMS/DRM バックエンドに似ています。

このアプローチの技術的な詳細については、このプレゼンテーションを参照してください。

Qt 5.7 では、このバックエンドは内部実装の多くを GBM ベースのバックエンドと共有しています。つまり、マルチスクリーンとQT_QPA_EGLFS_KMS_CONFIG を介した高度な設定がサポートされています。しかし、hwcursorpbuffers のようないくつかの設定は適用できません。

デフォルトでは、バックエンドは各出力のデフォルト平面に正しいEGLレイヤーを自動的に選択します。必要であれば、QT_QPA_EGLFS_LAYER_INDEX 環境変数に希望するレイヤーのインデックスを設定することで上書きできます。このアプローチは現在のところ複数の出力をサポートしていないので、その使用は単一のスクリーンを持つシステムに限定されるべきである。どのレイヤーが利用可能かを確認し、潜在的な起動時の問題をデバッグするには、ロギング・カテゴリーqt.qpa.eglfs.kms を有効にしてください。

場合によっては、希望する解像度がすでに設定されているとスクリーンに表示されても、アプリケーショ ンの起動時にビデオモードの設定を行う必要があるかもしれません。これは通常、最適化されますが、スクリーンがパワーダ ウンしたままになっている場合は、環境変数QT_QPA_EGLFS_ALWAYS_SET_MODE をゼロ以外の値に設定し、アプリケーショ ンを再起動してみてください。

バックエンドが使用するEGLStreamオブジェクトの動作を設定するには、環境変数QT_QPA_EGLFS_STREAM_FIFO_LENGTH 。これは、KHR_stream_fifo がターゲットシステムでサポートされていることを前提としています。デフォルトでは、ストリームはメールボックスモードで動作します。FIFOモードに切り替えるには、1以上の値を設定する。この値は、ストリームが保持できる最大フレーム数を指定する。

システムによっては、事前に定義されたコネクタを介して特定のオーバレイプレーンをターゲットにする必要が生じることがある。QT_QPA_EGLFS_LAYER_INDEX 経由でレイヤーインデックスを強制するだけでは、プレーンのコンフィギュレーションは実行されないため、それ自体適切ではない。そのような特殊なシナリオでは、代わりにQT_QPA_EGLFS_KMS_CONNECTOR_INDEXQT_QPA_EGLFS_KMS_PLANE_INDEX 環境変数を使用する。これらを設定すると、指定されたコネクターとプレーンのみが使用され、それ以外の出力は無視される。バックエンドは、希望するプレーンに対応するEGLレイヤーを選択し、プレーンを設定します。

KMS/DRM上の複数のスクリーンを持つシステムでのタッチ入力

タッチスクリーンはマルチディスプレイ・システムでさらに考慮する必要があります。なぜなら、タッチイベントは正しい仮想スクリーンにルーティングする必要があり、そのためにはタッチスクリーンとディスプレイ出力間の正しいマッピングが必要だからです。

このマッピングは、QT_QPA_EGLFS_KMS_CONFIG で指定され、前のセクションで説明した JSON 設定ファイルによって行われる。outputs 配列の要素にtouchDevice プロパティが存在する場合、その値はデバイス・ノードとして扱われ、タッチ・デバイスが当該ディスプレイ出力に関連付けられます。

例えば、タッチスクリーンが/dev/input/event5のデバイスノードを持ち、セカンダリスクリーンとしてHDMI経由で接続されたモニターに統合されたタッチスクリーンであると仮定すると、以下の設定により、タッチ(および合成マウス)イベントの正しい変換が保証されます:

 {
    "device": "drm-nvdc",
    "outputs": [
      {
        "name": "HDMI1",
        "touchDevice": "/dev/input/event5",
        "virtualIndex": 1
      },
      {
        "name": "DP1",
        "virtualIndex": 0
      }
    ]
}

注記: 疑問がある場合は、アプリケーションを起動する前に環境変数QT_LOGGING_RULES=qt.qpa.*=true を設定することで、グラフィックサブシステムと入力サブシステムの両方からのロギングを有効にしてください。これは正しい入力デバイスノードを特定するのに役立ち、デバッグが困難な出力設定の問題を発見するかもしれません。

注意: Qt 5.14では、上記はevdevtouchとlibinputバックエンドでのみサポートされています。その他のバックエンドは引き続きプライマリ・スクリーンにイベントをルーティングします。複数の入力バックエンドが利用可能なシステムでevdevtouchを強制的に使用するには、環境変数QT_QPA_EGLFS_NO_LIBINPUT1 に設定してください。

他のバックエンドを使用したEGLFS

他のバックエンドは通常、ベンダーのEGL実装を介してフレームバッファまたはコンポジションAPIを直接ターゲットにするため、マルチディスプレイのサポートは限定的であるか、まったく提供されません。Vivante GPUを搭載したi.MX6ベースのボードでは、QT_QPA_EGLFS_FB 環境変数を使用して、linuxfbと同様にターゲットとするフレームバッファを指定できます。Raspberry Piでは、QT_QPA_EGLFS_DISPMANX_ID 環境変数を使用して、出力先の画面を指定できます。この値はDISPMANX_ID_ 定数の1つに対応します。Dispmanx のドキュメントを参照してください。これらのアプローチは、KMS/DRMとは異なり、通常、同じアプリケーションから複数のスクリーンに出力することはできません。あるいは、ドライバ固有の環境変数やカーネルパラメータも、使用するフレームバッファを制御するために利用できるかもしれません。組み込みボードのドキュメントを参照してください。

ビデオメモリ

Qt Quick やQOpenGLWidget のようなクラスをベースとした Qt アプリケーションを実行する前に、専用のビデオメモリが一定量しかないシステムでは特に注意が必要です。特に、高解像度(例えば、フル HD)の画面に表示する場合、デフォルトの設定では不十分な場合があります。この場合、予期しない方法で失敗することがあります。少なくとも 128 MB の GPU メモリを確保することをお勧めします。GPU用に固定量のメモリーを予約していないシステムでは、これは問題ではありません。

linuxfb

fb プラグインパラメータを使って、使用するフレームバッファデバイスを指定します。

Unix シグナルハンドラ

eglfs や linuxfb のようなコンソール指向のプラットフォーム・プラグインは、割り込み (SIGINT)、サスペンドとコンティニュー (SIGTSTP,SIGCONT)、終了 (SIGTERM)をキャプチャするシグナル・ハンドラをデフォルトでインストールします。こうすることで、killCtrl+CCtrl+Z によってアプリケーションが終了したりサスペンドされたりしたときに、キーボードや端末カーソル、場合によってはその他のグラフィックスの状態を復元することができます(ただし、キーボードによる終了やサスペンドは、上記の入力セクションで説明したように、QT_QPA_ENABLE_TERMINAL_KEYBOARD が設定されている場合にのみ可能です)。しかし、SIGINT をキャプチャすることは、例えばリモート・デバッグと衝突する可能性があるため、望ましくない場合もある。そのため、すべてのビルトインシグナル処理をオプトアウトするための環境変数QT_QPA_NO_SIGNAL_HANDLER が用意されています。

フォント

Qt は通常、fontconfig を使用してシステム・フォントにアクセスします。fontconfig が利用できない場合、Qt はQBasicFontDatabase を使用します。この場合、Qt アプリケーションは Qt のlib/fonts ディレクトリからフォントを探します。Qt はプリレンダリングされたフォントと TrueType フォントを自動的に検出します。このディレクトリは、環境変数QT_QPA_FONTDIR を設定することで上書きすることができます。

サポートされているフォーマットの詳細については、Qt for Embedded Linux Fonts を参照してください。

注意: Qt はlib/fonts ディレクトリにフォントを同梱しなくなりました。つまり、必要なフォントを提供するのはプラットフォーム(システムイメージ)次第です。

組み込み Linux デバイスのウィンドウシステム用プラットフォームプラグイン

XCB

これは通常のデスクトップLinuxプラットフォームで使われるX11プラグインです。Xとxcbに必要な開発ファイルを提供するいくつかの組み込み環境では、このプラグインは通常のPCデスクトップと同じように機能します。

注意: デバイスによっては、EGL実装がXlibと互換性がないため、XではEGLとOpenGLのサポートがありません。この場合、XCBプラグインはEGLサポートなしでビルドされ、Qt Quick 2や他のOpenGLベースのアプリケーションはこのプラットフォームプラグインでは動作しません。しかし、ソフトウェアレンダリングされたアプリケーション(たとえばQWidget ベース)を実行するために使用することはできます。

一般的なルールとして、組込み機器でのXCBの使用はお勧めできません。eglfsのようなプラグインは、より良いパフォーマンスとハードウェアアクセラレーションを提供する可能性があります。

ウェイランド

より正確には、クライアントがディスプレイサーバーと通信するためのプロトコルです。

Qt Waylandはwayland プラットフォーム・プラグインを提供し、QtアプリケーションがWaylandコンポジターに接続できるようにします。

詳細はWaylandとQtを参照してください。

パフォーマンス向上のガイドライン

可能な限りハードウェアレンダリングを使用する

アプリケーションのパフォーマンスが重要な場合、Qt Charts のようなソフトウェアレンダリングに依存する Qt モジュールの使用は避けてください。可能であれば、ハードウェアレンダリングに依存するモジュールを使用してください。

Qt Quick のベストプラクティスに従ってください。

QML と Qt Quick のベストプラクティスに従ってください。特にQML CMake API をインクルードして、qmllintQML スクリプトコンパイラ(qmlsc)、QML タイプコンパイラ(qmltc)を利用できるようにしてください。また、宣言的なQMLを記述し、Javascriptを最小限にすることが望ましいです。過剰なJavaScriptの使用によるパフォーマンスへの影響については、QML Performance Considerations And Suggestionsを参照してください。

Canvas QMLタイプの代わりに、画像やテクスチャ、シェーダー効果を使う

カスタムUIエレメントの描画には、イメージ/テクスチャやシェーダーエフェクトを使用してください。QMLCanvas タイプは使わないでください。シェーダにはハードウェアアクセラレーション(GPU)が必要です。

Qt ウィジェットの代わりに Qt Quick を使う

Qt Quick では、ハードウェアアクセラレーションまたはソフトウェアレンダリングのバックエンドを使用できます。複雑な Ul の場合、組み込みターゲットで Qt Widgets を使用することは推奨されません。

ここにはトレードオフがあります:

  • QML エンジンと Qt Quick の使用には、初期のオーバーヘッドが伴います。
  • QML エンジンと Qt Quick を使用すると、初期オーバーヘッドが発生します。UI が非常にシンプルで、めったに再描画されない場合、QML ではなく Widgets を使用した方が高速に動作する可能性があります。
  • UI にアニメーションsmooth scrollingscalingrendering effects3D を使用する場合は、GPU アクセラレーションが必要です。

UI サイズに適した解像度を選ぶ

高解像度には注意が必要です。720p 以上の解像度はパフォーマンスを低下させる可能性があります。

アプリケーションのルート要素として QML Window タイプを使用する。

アプリケーションのルート要素にはWindow を使用し、アプリケーションの背景はcolor とします。

その理由は、Windowコンポーネントにはバッファクリアの効果を持つカラー プロパティがあるからです。アプリケーションのルートItem としてフルスクリーンRectangle を使用して背景をレンダリングすると、追加の描画呼び出しが発生します。RHIのバックエンドによっては、これは同じことかもしれませんが、glClear の呼び出しと四角形の描画には違いがあります。ほとんどの場合、単一の不透明な画像はパフォーマンスに大きな影響を与えないかもしれませんが、そのアイテムの色にアルファ値を使用する場合は、パフォーマンスに大きな影響を与える可能性があります。

本ドキュメントに含まれる文書の著作権は、それぞれの所有者に帰属します。 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。