編集:レンダラーの分離問題全体に対する優れた解決策を以下に投稿しました。
私は最近、マルチスレッド X11 環境で OpenGL をいじっています。次のチュートリアルを見つけました。これは、コンパイル、リンク、および正常に実行されます。
その後、自分のニーズに合わせてコードを調整しようとした後、奇妙な問題に遭遇しました。
チュートリアルでは、XCreateWindow、glXCreateContext、XSelectInput、および XSetWMProtocols の呼び出し順序は次のとおりです。
param[i].win = XCreateWindow(param[i].d_, root, 200,200,
300,200, 0, visInfo->depth, InputOutput, visInfo->visual,
CWColormap,
&windowAttr);
param[i].ctx = glXCreateContext(param[i].d_, visInfo, NULL, True);
XSelectInput(d, param[i].win, StructureNotifyMask);
XSetWMProtocols(d, param[i].win, &(delMsg), 1);
XCreateWindow と XSelectInput/XSetWMProtocols は異なるディスプレイ接続を使用することに注意してください。
ただし、呼び出しの順序を変更すると、
param[i].win = XCreateWindow(param[i].d_, root, 200,200,
300,200, 0, visInfo->depth, InputOutput, visInfo->visual,
CWColormap,
&windowAttr);
XSelectInput(d, param[i].win, StructureNotifyMask);
XSetWMProtocols(d, param[i].win, &(delMsg), 1);
param[i].ctx = glXCreateContext(param[i].d_, visInfo, NULL, True);
プログラムは失敗します
失敗した要求の X エラー: BadWindow (無効なウィンドウ パラメータ)
失敗した要求のメジャー オペコード: 2 (X_ChangeWindowAttributes)
失敗した要求のリソース ID: 0x5000002 失敗した要求のシリアル番号: 17 出力ストリームの現在のシリアル番号: 18
XSetWMProtocols が原因のようです。
異なるディスプレイ接続が使用されていたので、そもそも全体が機能しなくても驚かないでしょう。しかし、どういうわけか、glXCreateContext を呼び出した後は、すべてが魔法のようにうまくいっているように見えます。
私は X11/GLX プログラミングに比較的慣れていません。glXCreateContext はどのような魔法を実行しますか? それとも何か他のことが起こったのですか?または、OpenGL とマルチスレッドは常に問題を引き起こすように見えるため、単に先に進む必要があるかもしれません。
私の解決策:
私は怠け者で、チュートリアルのアプローチを使用していました。私のプロジェクトにfreetypeを追加するまではうまくいきましたが、突然BadWindowが再びクラッシュしました。そのため、たとえすべてがうまくいっているように見えても、別のスレッドで作業している場合、X11 は、あなたがいない間にメモリをいじくり回しています。(私ではありませんでした。valgrind で確認しました)
私の現在の解決策は nm がコメントしたとおりです。私はすべてを GUI スレッド (X11 および GL/GLX 呼び出し) に入れました。そのリソースは他のスレッドでは決して利用できません。ただし、レンダリング ループが遅くなる可能性があるため、次の 2 つの点に注意する必要があります。
- メッセージ処理が遅いとレンダリングが遅れます(以下のilmaleが述べているように)
- 遅いレンダリングはメッセージ処理を遅らせます (私の懸念事項)
最初の問題は簡単に修正できます。アプリ ロジックに関連する XEvents をキューに入れ、別のスレッドからそれらを取得する stl デキューまたはリスト、または任意のコンテナーを作成します。STL がスレッドセーフであることを確認し、疑わしい場合は独自のキューを実装してください。コンテナーのサイズに待機条件を設定すると、XNextEvent などのブロッキング呼び出しをシミュレートすることもできます。
2 つ目の問題は厄介です。レンダラーが 1 fps 以下の場合、ゲームやアプリケーションは役に立たないと主張するかもしれません。それは本当です。しかし、たとえ 0.1 fps であっても、いくつかの kill シグナル (ウィンドウの破棄アトムなど) を処理できれば素晴らしいことです。私が考えることができる唯一の解決策は、約1000個のスプライトごとにレンダリングした後に新しいメッセージをチェックすることです. それらをコンテナに送信し、レンダリングを続行します。もちろん、その場合、レンダリング スレッドにユーザー スクリプトやその他の未知のコードを実行させることはできません。しかし、それでは、レンダリングを他のスレッドから分離するという考えは無意味になると思います。
お役に立てれば。
: