OS-X でC++アプリケーション(GLFW3)

BqNTjU-CEAArsW9

今まで、自分で細々と作っているフレームワークはGLFW3をベースにしているものの、Windows 環境しかテストしていなかった。
MacBook Pro を買ったので、Mac に対応させるべく作業をした。
最近はフルタイムで仕事をしているので、自分のプログラミングは時間が限られる、最近ようやく、Windows 版と遜色なく動作するようになったので、要点をまとめてみたい、同じような事をしている人に参考になればと思う。

・カレントディレクトリーの扱いが違う。
アプリケーションが動作しているカレントディレクトリーの、挙動が異なるようだ。
Mac(unix) では基本的に、コンソールから起動した場合と、finder などから起動した場合で、main 関数のパラメーター「argv[0]」に入ってくるパスが異なる。
unix では、アプリケーションのカレントディレクトリーの管理は、シェルが行っており、シェルから起動しない場合を想定しておく必要がある。

Windows では、アプリを起動させたパスをカレントパスとして設定している。

良く、アプリを置いたパスに初期に読み込むファイルなどを置いておく事があるけど、何らかの方法で、相対パスから絶対パスを生成する必要がある。
自分は、「argv[0]」にアプリケーションの起動パスがあるので、それを使って何とかした。
※また、シェルから起動した場合は、argv[0]には、「./xxxx」など、シェルのコマンドラインがそのまま反映されるだけなので、「getcwd」APIなどで、カレントディレクトリーを取得する必要がある。
しかしながら、「getcwd」は、シェルから起動しないと正しいパスを返さないようだ。

・ランタイムライブラリー(要するに DLL、unix 的にはシェアードライブラリー?)
OS-X では、コンパイル時のライブラリーのリンクが固定していて、実行バイナリーを他の環境に持って行く場合には、ライブラリーを期待した場所に置いておく必要がある。(これは設定ファイルで変えられるかもしれないが調べていない)
俺俺フレームワークでは、色々なオープンソースを使っているのだけど、OS-X ではコンソールからコンパイルしてインストールすのが、比較的楽なので、問題は少ないかもしれない。

・システムフォントのパス
当然だけど、OS-X では、フォントパスが違うので、それを対応する必要がある。
ちなみに

/System/Library/Fonts

となる、標準的日本語フォントは

ヒラギノ角ゴ ProN W3.otf

を使っている。

・コンソールの扱い
Windows(mingw)では、リンカーのオプションに「-m window」があり、コマンド起動後にコンソールを表示して、stdout や stderr の表示をするなどに対応出来るけど、OS-X では、必ずコンソールも起動してしまう。
コンソールが必要無い場合はどうするのか?、謎だったけど、色々調べたら、フォルダーで全体を管理するようだ、その際、アプリケーションのアイコンやら、何やら、色々な設定を「info.plist」の XML ファイルに記述する方法のようで、Windows のアプリケーションとは全く考えが違う。

・解像度に対しての対応
MacBook Pro riteina では、高解像度の液晶を使っている、解像度が高い為、見た目の大きさを揃える為には、Window の仮想サイズと、実際のサイズ(フレームバッファのサイズ)が異なり、それ相応の対処をしなければならない。
OpenGLでは、「glViewport」で指定するサイズは、実際の解像度ベースで指定して、プロジェクションマトリックスで指定する大きさは、仮想サイズで指定することになる。
仮想サイズは、実際のサイズの丁度半分となるようだけど、自由なサイズに対応しておく必要がありそうだ。

・スレッド
OS-X は pthread に対応との事だが、pthread の仕様を全て満足している訳では無く、使えるのは一部の API だけなので注意が必要だ、特に悲惨なのは、コンパイルは通るけど、API は何もしないで、エラーコードと共に素通りする。
※名前無しセマフォなど
※現状では、POSIX の API に完全に全て対応しているのは Linux カーネルのみなのかもしれない。
OS-X で pthread のプログラムを作成する場合には、注意して設計する必要がある。
boost や、C++11 の API を使うのが賢いかもしれない。
ただ、現状では、Mingw の環境では、C++11 でも、thread をサポートしていない為、マルチプラットホームでは、コードを共有出来ない。
※一方 Windows には、pthread_win32 ライブラリーがある為、pthread のプログラムを作成するのに、問題は少ない。

・OpenGL プログラムのスワップフレーム
OS-X では、OpenGL のプログラムを待機状態にしたり、他の Window で全て隠すと、スワップフレームが画面のリフレッシュと同期しなくなり素通りになる為、実質的に、描画ループが最高速で回り始める、そうすると、CPU の空き時間を全て食いつぶして負荷が100%に近くなる。
これは、色々調べたけど、「仕様」のようだ、そこで、この問題を回避する対策が必要だ。
自分のアプリケーションは、GLFW3 を介して、システムと繋がっている為、「待機状態」を検出する方法が無い為、別の方法で、この問題を回避した。
(1)16ミリ秒のタイマータスクを用意する。(usleep、nanosleep など)
※ OS-X の sleep 系は意外と正確なようだ。(Windows のタイマーが不正確すぎなのかもしれない)
(2)フレームの先頭で、先に用意したタスクをスレッドで起動する。(C++11 の future を利用した)
(3)スワップフレームの手前で、先のスレッドの終了を待つ。
この戦略は、フレームレートが 60Hz(16.677ミリ秒) の場合、タイマーが正確な場合を前提としている。
※オーバーヘッドが、0.677 ミリ秒より大きい場合は、待機時間を調整する必要がある。
※スレッドの追加で、システムの負荷が1〜2%増加する。(意外と重い)
※プログラムは、common/glcore.hpp, common/glcore.cpp を参照
※ Windows では、プログラムが待機状態になると、メインループは停止するので、回り続ける仕様自体は、歓迎されるべきなのかもしれない。
なので、Windows では、動かし続ける必要のあるタスクは、メインループに依存しないように設計する必要がある。

--------------------

OS-X は、実質 unix マシンなので、X-code を利用しなくても、コンソールとテキストエディターだけで、遜色無くアプリケーションを開発できて、非常に快適な事が判った。
コンソールは多国語対応で(当然日本語にも)、複雑な設定をする事なく、日本語をスマートに入力、表示出来る。
emacs もコンソールで起動でき、日本語入力にも対応している。
今まで食わず嫌いで、OS-X を使わなかったけど、まぁ、なかなか良い。