FPSを作ってみる@wiki
01)
最終更新:
slice
-
view
(2014/01/23)
Kdevelop(Kd)がイケてないからQtCreator(以下Qc)にすると言った矢先
QcはQcでデバッガやUIは問題ないもののエディット時に勝手に構文解析が走って
0.5秒とか無視できない範囲でプチフリーズが頻発するから困る。
Kdもそうなんだけどここまで酷くはなかった。
QcはQcでデバッガやUIは問題ないもののエディット時に勝手に構文解析が走って
0.5秒とか無視できない範囲でプチフリーズが頻発するから困る。
Kdもそうなんだけどここまで酷くはなかった。
そもそも両者混みいったC++のキーワードを補完してくれないので「やっぱりVisualC++のIntelliSenseはサイコーだったな・・」と、
遠い目をする事多し。
エディタが使いにくいと制作意欲へのダメージも結構なもので、
プログラマはエディタにこだわると言われるのは好みの問題なんかではなく必然なのだ。
遠い目をする事多し。
エディタが使いにくいと制作意欲へのダメージも結構なもので、
プログラマはエディタにこだわると言われるのは好みの問題なんかではなく必然なのだ。
ここで気になるのがClangの構文解析エンジンを利用したVimの補完プラグインの存在で、早速Vimの復習から入り
.vimrcをみようみまねで書いてclang_completeやneobundle, neocomplete等を導入。
補完機能をひと通り試してみた。
ソースがマクロマクロしていてもメンバ変数や関数をちゃんと補完してくれるのはIntelliSenseを離れた身としては感動ものである。
補完の速度もまずまずだし、なんならオート補完を切ることもできる。
.vimrcをみようみまねで書いてclang_completeやneobundle, neocomplete等を導入。
補完機能をひと通り試してみた。
ソースがマクロマクロしていてもメンバ変数や関数をちゃんと補完してくれるのはIntelliSenseを離れた身としては感動ものである。
補完の速度もまずまずだし、なんならオート補完を切ることもできる。
残るはビルドコマンドやデバッグ環境の整備だが・・
ビルドコマンドはまたの機会にするとしてデバッグはこれからもQtCreatorのお世話になりそう。
関数や変数の定義に一発で飛ぶプラグインとかも調べないといかんね。
ビルドコマンドはまたの機会にするとしてデバッグはこれからもQtCreatorのお世話になりそう。
関数や変数の定義に一発で飛ぶプラグインとかも調べないといかんね。
そんな訳で現状エディットはgVimで、ビルドとデバッグはQtCreatorという形になっている
ゲームの方
くだらないミスをして一回休み。
ウィンドウが最小化されるとOpenGLのリソースを全開放、復帰させる仕様なのは承知の通り。
FPS値を表示するために毎フレーム文字列テクスチャを作成して表示するような事をしていて
1. メインスレッドがフォントテクスチャを作成、描画スレッドに渡す用のバッファに入れる
FPS値を表示するために毎フレーム文字列テクスチャを作成して表示するような事をしていて
1. メインスレッドがフォントテクスチャを作成、描画スレッドに渡す用のバッファに入れる
この時OpenGLのリソース値を直接記載
2. ウィンドウ最小化
3. 描画スレッドが(すでに破棄された)フォントテクスチャを使う
4. エラー発生!
という流れでPCがフリーズしたりSEGVで落ちたりしてた。
3. 描画スレッドが(すでに破棄された)フォントテクスチャを使う
4. エラー発生!
という流れでPCがフリーズしたりSEGVで落ちたりしてた。
場合によってエラーになったりならなかったりするんでかなり苦戦。
(2014/01/21)
描画スレッド
描画スレッドの実装、完了。そこそこ苦戦というか。
今までは例えばテクスチャのフィルタリング方式を変更したいとなった場合に即OpenGL APIを呼んで変更を伝えれば良かったが
マルチスレッドにした関係上すぐに変更しては描画スレッドがテクスチャを使っていた場合に不具合(最悪落ちる)が起こるので
次回描画スレッドが動いた時まで遅延させる等の処理が必要となった。
更にちょうどその時フレームスキップが起こったら変更が反映されないのでスキップされた時でも対処できるような仕組みとか、色々。
今までは例えばテクスチャのフィルタリング方式を変更したいとなった場合に即OpenGL APIを呼んで変更を伝えれば良かったが
マルチスレッドにした関係上すぐに変更しては描画スレッドがテクスチャを使っていた場合に不具合(最悪落ちる)が起こるので
次回描画スレッドが動いた時まで遅延させる等の処理が必要となった。
更にちょうどその時フレームスキップが起こったら変更が反映されないのでスキップされた時でも対処できるような仕組みとか、色々。
結果としてOpenGLのテクスチャとか頂点バッファ等の関連クラスを半分以上書き換える形に。
シングルスレッドで動いていたものを後からマルチスレッドにするのは大変だ。
シングルスレッドで動いていたものを後からマルチスレッドにするのは大変だ。
アルゴリズムが上手く動いていれば描画スレッドが描画ソート(予定)と描画コールしてる間に
メインスレッドが次フレームのゲーム処理や描画タスクの準備をして
描画タスクはダブルバッファになってるのであるタイミングでそれを切り替えて・・・という感じで進む筈。
メインスレッドが次フレームのゲーム処理や描画タスクの準備をして
描画タスクはダブルバッファになってるのであるタイミングでそれを切り替えて・・・という感じで進む筈。
残る問題
シングルContextの時にデッドロックする問題が残っていて一応原因は判明してるものの・・ま、どうでしょう。
すぐ修正できればいいけど。
あとシングル時にメインスレッドでOpenGL関数を呼ぶと描画スレッドにポストして描画スレッドが暇になった時に処理、メインスレッドはそれが終わるまで待機という設計なんだけど
現状では「暇になった時 = フレームの描画をし終えた時」だけなので場合によっちゃかなり待たされるかもしれない。
適度にメッセージループを回してあげる必要がある。(でも面倒なので後)
すぐ修正できればいいけど。
あとシングル時にメインスレッドでOpenGL関数を呼ぶと描画スレッドにポストして描画スレッドが暇になった時に処理、メインスレッドはそれが終わるまで待機という設計なんだけど
現状では「暇になった時 = フレームの描画をし終えた時」だけなので場合によっちゃかなり待たされるかもしれない。
適度にメッセージループを回してあげる必要がある。(でも面倒なので後)
(2014/01/15)
また間が空きそうなのでここで一旦報告。
ContextSharing出来ない環境
OpenGL APIでContext Sharingが利用できない環境(主に古いビデオドライバやAndroid)の対処を行った。
SharingしてるならそのままAPIを呼び、そうでないなら描画スレッドに要求をポストして終わるまで待つ。
言葉にするとたった一行なんだけど今までに使ったAPIを全箇所修正したり
描画スレッドにポストする部分の実装(APIに戻り値がある時の対処。voidの扱いなど)や、
リソースの開放順序が不味いらしく
アプリケーション終了時にSharing環境では問題ないのにSharingしてない場合だとSEGVになるとかあって結構時間かかった。
SharingしてるならそのままAPIを呼び、そうでないなら描画スレッドに要求をポストして終わるまで待つ。
言葉にするとたった一行なんだけど今までに使ったAPIを全箇所修正したり
描画スレッドにポストする部分の実装(APIに戻り値がある時の対処。voidの扱いなど)や、
リソースの開放順序が不味いらしく
アプリケーション終了時にSharing環境では問題ないのにSharingしてない場合だとSEGVになるとかあって結構時間かかった。
引き続き
描画のマルチスレッド対応に関する作業を続ける。
次はメインスレッドから描画スレッドにタスクを投げてゲーム進行とは別に描画させる処理。
こちらも苦戦が予想されるが、果たして・・
次はメインスレッドから描画スレッドにタスクを投げてゲーム進行とは別に描画させる処理。
こちらも苦戦が予想されるが、果たして・・
(2014/01/10)
詳細という程でもなかった
詳細は後日。などと書くと
「ちゃんとした記事にしなきゃいけないのでは。もうちょっとネタが溜まってから整理して書くべきなのでは」
となって億劫になる事がわかった。なので今後そういうのは無しにする。
前回に関して言えば単に説明文を考えるのが面倒という理由だけで「詳細は後」と書いてしまったのが失敗の要因である。
肩の力を抜いて不定期更新、記事の質もバラバラとした方が更新を継続する点で有利か。
「ちゃんとした記事にしなきゃいけないのでは。もうちょっとネタが溜まってから整理して書くべきなのでは」
となって億劫になる事がわかった。なので今後そういうのは無しにする。
前回に関して言えば単に説明文を考えるのが面倒という理由だけで「詳細は後」と書いてしまったのが失敗の要因である。
肩の力を抜いて不定期更新、記事の質もバラバラとした方が更新を継続する点で有利か。
windows版
散々苦戦したけどwindows版がサウンド、グラフィックなど全部linux版と同じ様に動いた。
- win8で30fpsになってしまう問題
これは割と単純。winXPはVSyncがデフォルトでOff, win8はOnになっているんだけど
ゲームの更新タイミングは自前で管理しているのでVSyncの同期待ちとアプリケーションのそれが微妙に噛み合わない時に
フレームスキップ機能が働いて1フレームスキップされて30fpsになっていた。
従ってOpenGLのVSyncを明示的にOffにすれば解決。
ゲームの更新タイミングは自前で管理しているのでVSyncの同期待ちとアプリケーションのそれが微妙に噛み合わない時に
フレームスキップ機能が働いて1フレームスキップされて30fpsになっていた。
従ってOpenGLのVSyncを明示的にOffにすれば解決。
- winXP, win8両方でウィンドウを最小化した後にポリゴンが描画されなくなってしまう問題
原因の特定までかなり苦戦した。linuxやwineで発生しなくてwindowsだと確実に発生するという。
結論から言えばグラフィックボードのドライバに起因した問題。
(wineはlinuxのドライバを使う)
何故描画されないかと言えば、深度テストに失敗していた。
ちゃんとglClearDepth()とglClear(GL_DEPTH_BUFFER_BIT)で初期化したと思っても
設定によっては深度バッファがクリアされない時があるのだ。
結論から言えばグラフィックボードのドライバに起因した問題。
(wineはlinuxのドライバを使う)
何故描画されないかと言えば、深度テストに失敗していた。
ちゃんとglClearDepth()とglClear(GL_DEPTH_BUFFER_BIT)で初期化したと思っても
設定によっては深度バッファがクリアされない時があるのだ。
当方RadeonなのでGeForceは知らないが少なくともAMD Catalystドライバ環境で
glDepthWrite(GL_FALSE)でZの書き込みをOffにしたまんまglClear(GL_DEPTH_BUFFER_BIT)を呼んだ際
linux(ubuntu 32bit)版のドライバでは深度バッファがクリアされるが
winXP(32bit), win8(64bit)版では何も起こらない。
glDepthWrite(GL_FALSE)でZの書き込みをOffにしたまんまglClear(GL_DEPTH_BUFFER_BIT)を呼んだ際
linux(ubuntu 32bit)版のドライバでは深度バッファがクリアされるが
winXP(32bit), win8(64bit)版では何も起こらない。
はい。非常に大事なことなのでもう一度。
深度バッファをクリアする時は必ず
深度バッファをクリアする時は必ず
glDepthWrite(GL_TRUE); glClear(GL_DEPTH_BUFFER_BIT);
こうね。
- win8でウィンドウを最小化した後にフリーズする
上記の原因究明でソースコードを色々いじってたらいつの間にか発生しなくなっていた。
恐らくOpenGLコンテキスト解放のタイミングを変えた時だったと思うが・・
(OpenGLのリソースを全て開放した後にコンテキストを解放するつもりが、そうなってなかった)
恐らくOpenGLコンテキスト解放のタイミングを変えた時だったと思うが・・
(OpenGLのリソースを全て開放した後にコンテキストを解放するつもりが、そうなってなかった)
ゲームスレッドと描画スレッド
ゲームとして動かすには依然として問題が。
現状ゲーム進行や当たり判定等の処理を行うゲームスレッドとOpenGLのAPIを呼んでGPUにコマンドを送る描画スレッドが分かれているのに
そのあたりのデータ管理とか同期を全く実装してない。
今まではテスト用にポリゴン一枚表示出来れば良くて、描画スレッド側でポリゴン座標や頂点バッファの初期化をしていたから
問題にならなかっただけの話だ。
でも描画スレッドでデータの読み込みや何やらしてたのでは折角スレッドを分けた意味がない訳で。何とかしなきゃイカンと。
現状ゲーム進行や当たり判定等の処理を行うゲームスレッドとOpenGLのAPIを呼んでGPUにコマンドを送る描画スレッドが分かれているのに
そのあたりのデータ管理とか同期を全く実装してない。
今まではテスト用にポリゴン一枚表示出来れば良くて、描画スレッド側でポリゴン座標や頂点バッファの初期化をしていたから
問題にならなかっただけの話だ。
でも描画スレッドでデータの読み込みや何やらしてたのでは折角スレッドを分けた意味がない訳で。何とかしなきゃイカンと。
それとOpenGLのContextSharingが利用できない状況(主にAndroid)ではContextを1つだけ作って描画スレッドに持たせ、
メインスレッドから何かOpenGL APIを使った処理をしたい場合は描画スレッドにタスクを投げて処理してもらう仕組みも必要なんだが
それもまだ。
一応スレッド同期のデータ構造と「だいたいこんなんかな〜」といったアルゴリズムのメモ書きくらいはあるけど。
メインスレッドから何かOpenGL APIを使った処理をしたい場合は描画スレッドにタスクを投げて処理してもらう仕組みも必要なんだが
それもまだ。
一応スレッド同期のデータ構造と「だいたいこんなんかな〜」といったアルゴリズムのメモ書きくらいはあるけど。
(2014/01/08)
取り急ぎ急いでないけどwindowsでも完動しました報告。
スクリーンショットのためにウィンドウを無理やり小さくしたので文字がボサボサなのは仕様。
imageプラグインエラー : ご指定のファイルが見つかりません。ファイル名を確認して、再度指定してください。 (sdl_winxp.png)
スクリーンショットのためにウィンドウを無理やり小さくしたので文字がボサボサなのは仕様。
詳細はまた後で。
(2014/01/07)
自作エンジンがwineで動いたし、前回の修正によりwindowsでもフリーズすることなく動いた・・・これで安心
とは行かず、例によって例のごとく不具合発生。しかもwinXPとwin8で挙動が違っていた。
具体的には
winXP: 60fpsで動作。ウィンドウ最小化した後の復帰時はサウンドも問題ないが、何故かポリゴンの描画がされなくなる(画面クリアは効く)
win8: 30fps位で動作。ウィンドウ最小化した後のサウンドも問題ないが、フリーズする(恐らくOpenGL API関連)
更にvirtualboxへインストールしたwinXPでも試したらこちらはOpenGLのContextSharingに対応してない様子で描画出来ず。
winXPとwin8で動作速度が違うのは垂直同期設定のデフォルトが異なってるからだろうと思い、インターバルを0にしてみるも改善されなかった。
具体的には
winXP: 60fpsで動作。ウィンドウ最小化した後の復帰時はサウンドも問題ないが、何故かポリゴンの描画がされなくなる(画面クリアは効く)
win8: 30fps位で動作。ウィンドウ最小化した後のサウンドも問題ないが、フリーズする(恐らくOpenGL API関連)
更にvirtualboxへインストールしたwinXPでも試したらこちらはOpenGLのContextSharingに対応してない様子で描画出来ず。
winXPとwin8で動作速度が違うのは垂直同期設定のデフォルトが異なってるからだろうと思い、インターバルを0にしてみるも改善されなかった。
とりあえずプログラムをシンプルにしてGLSLを使わない昔ながらのglBegin()〜glVertex3f()〜glEnd()の形式で
描画してみたらこれは普通に動くので、これはGLSLかVBOやIBOの設定で何かミスってる可能性大。
描画してみたらこれは普通に動くので、これはGLSLかVBOやIBOの設定で何かミスってる可能性大。
(2014/01/05)
ここに来て大域照明に興味が出だしたけどここはグッとこらえてweb記事を見るだけにしておく。
その前に基本的なシャドウマップをやっておきたい。
その前に基本的なシャドウマップをやっておきたい。
windows版の不具合
windows版でアプリケーション終了時にフリーズしてしまう問題。
かなり究明に時間を食ってしまったが
thread_local(TLS)宣言した変数を、std::threadを介さずwindowsのCreateThreadや_beginthreadexを通して触っていた事が原因のようだ。
std::thread以外のAPIで作った子スレッドからTLS変数を参照すると子スレッドのルーチンが終了した後でも
親スレッドからは終了とみなされずそこで固まってしまう。
ちなみに親スレッドからTLS変数を使う分には問題ないが、たまたま上手く動いてるだけとも限らない。
かなり究明に時間を食ってしまったが
thread_local(TLS)宣言した変数を、std::threadを介さずwindowsのCreateThreadや_beginthreadexを通して触っていた事が原因のようだ。
std::thread以外のAPIで作った子スレッドからTLS変数を参照すると子スレッドのルーチンが終了した後でも
親スレッドからは終了とみなされずそこで固まってしまう。
ちなみに親スレッドからTLS変数を使う分には問題ないが、たまたま上手く動いてるだけとも限らない。
あとこれはwineでのみ発生する不具合なのだがサイズ固定のウィンドウを一旦最小化してもとに戻すと
60x60位のサイズに復元されてしまい、サイズ固定なのでユーザーはにっちもさっちも行かなくなる。
この為wineで試す際はRESIZABLEに設定する必要があった。
60x60位のサイズに復元されてしまい、サイズ固定なのでユーザーはにっちもさっちも行かなくなる。
この為wineで試す際はRESIZABLEに設定する必要があった。
#追記
上記のフリーズ問題を解決し、ようやくWindows版が動く段階まで来た。
現時点で予定してるデモは
- サウンドの再生、停止、ウィンドウの最小化による一時停止と復帰
- OpenGLによるポリゴン表示
- キーボードとマウス入力
- 文字列描画
- ファイル読み込み
要するにOpenGLとSDLとFreeTypeとOpenALのテスト。
見た目としては前に書いたように画面中央に立方体が回ってるだけなので、ぶっちゃけ動かしても面白くないと思う。
しかし作業を一旦区切る意味でもここらでアップしておこうかと。
しかし作業を一旦区切る意味でもここらでアップしておこうかと。
その後はAndroidで動かしてみるか、ゲームっぽいもの作ってみようか、
視覚に訴える要素(リアルタイムシャドウ)でも入れようか・・・迷っている
視覚に訴える要素(リアルタイムシャドウ)でも入れようか・・・迷っている
(2014/01/04)
ぼちぼちWindows版が動いてる
フォントをLinuxと同じ様に表示できて、キー入力もちゃんと効く。音も大丈夫。
年明け丸3日経ってまだそこか!っていう意見については、まぁ、そうだねぇとしか。
フォントをLinuxと同じ様に表示できて、キー入力もちゃんと効く。音も大丈夫。
年明け丸3日経ってまだそこか!っていう意見については、まぁ、そうだねぇとしか。
で、大体動きはするんだけどアプリケーション終了時、スレッドの同期のとこでwindows版だけが内部でデッドロックしてるのか止まってしまって調査中。
linux版はちゃんと動くのに、何が悪いのか。
linux版はちゃんと動くのに、何が悪いのか。
#追記
とりあえず今回はバグの原因を大体突き止めたから良いものの
相変わらずMinGWでコンパイルしたプログラムのデバッグ効率が悪すぎる。
なんかwin機をリモートで動かしてデバッグというのが出来るらしいが、自分にそこまでのスキルが無い。
相変わらずMinGWでコンパイルしたプログラムのデバッグ効率が悪すぎる。
なんかwin機をリモートで動かしてデバッグというのが出来るらしいが、自分にそこまでのスキルが無い。
(2014/01/01)
自作ライブラリを組み込んだプログラムをMinGW一回ビルドするのに
最後のリンクだけで1分は余裕で掛かるの何とかして欲しい。
(ちなみにLinux用は20秒程度)
最後のリンクだけで1分は余裕で掛かるの何とかして欲しい。
(ちなみにLinux用は20秒程度)
パス
通常、linuxでパスを記述する時は
絶対: /AAAA/BBBB
相対: CCCC/DDDD
のようにして
絶対: /AAAA/BBBB
相対: CCCC/DDDD
のようにして
windowsのパスだと
絶対: C:\AAAA\BBBB
相対: CCCC\DDDD
という感じになる。
絶対: C:\AAAA\BBBB
相対: CCCC\DDDD
という感じになる。
パスクラスに入力する時はスラッシュとバックスラッシュを自動で統一するようにしたんだけど先頭のドライブ文字の対応を忘れていた。
対応しなければ・・
対応しなければ・・
(2014/01/01)
新年あけまして進捗どうでしょう?<●> <●>
駄目でした><
等とやってる場合じゃない、ことよろ。
アラインメントずれの原因
先日触れたalignas(16)してるのに16byteアラインされてない問題を、あれからもう少し調べてみた。
SDL_Threadが絡んでるのはほぼ確定かなと。
具体的にはMinGW w64 & SDL2においてSDL_CreateThread()でスレッドを作成し、子スレッドでalignas(16)した構造体やクラスをスタックに置くとずれる。
SDL_Threadが絡んでるのはほぼ確定かなと。
具体的にはMinGW w64 & SDL2においてSDL_CreateThread()でスレッドを作成し、子スレッドでalignas(16)した構造体やクラスをスタックに置くとずれる。
ずれる幅の条件がいまいちわかってないのだが
自分の環境だとmainからすぐスレッド作ってその内部のスタックで
アラインメント指定の構造体を作ると4byteずつズレている。
windowsプログラムでは本来WinMainから始まるが
SDLmainによりlinux等と同じ様にmain関数から始まるようにすると今度は8byteずれる。
孫スレッドを作ってみてもズレ幅は変わらないようだ。
自分の環境だとmainからすぐスレッド作ってその内部のスタックで
アラインメント指定の構造体を作ると4byteずつズレている。
windowsプログラムでは本来WinMainから始まるが
SDLmainによりlinux等と同じ様にmain関数から始まるようにすると今度は8byteずれる。
孫スレッドを作ってみてもズレ幅は変わらないようだ。
ちなみにWinAPIのCreateThread()や、_beginthreadex()ではズレない。
SDL_Threadのソースをちらっと見ると内部で同じ様に上記の関数を呼んでいるが・・・?
インラインアセンブラ使ってる部分がちょっと怪しい。
この辺はもうちょっと読まないとわからないか。
SDL_Threadのソースをちらっと見ると内部で同じ様に上記の関数を呼んでいるが・・・?
インラインアセンブラ使ってる部分がちょっと怪しい。
この辺はもうちょっと読まないとわからないか。
最初はSDLのビルド済みMinGW用バイナリが変なのかなと思い、自分でリポジトリから取ってきてビルドしてみたけど変わらず。
勿論ググった所で探し方が悪いのか何も出やしない
こうなると自分でライブラリのパッチを作るか諦めてwindowsで動くpthreadライブラリを使うなど別の手段をとるかになる。
pthreadで統一するのも悪くはないが、あまりSDL以外のライブラリに依存するとSDLを使う意義が薄れる。
もし3,4行の修正でSDL_Threadが動くならその方が楽なのだが。アラインメントの問題だけだし。
勿論ググった所で探し方が悪いのか何も出やしない
こうなると自分でライブラリのパッチを作るか諦めてwindowsで動くpthreadライブラリを使うなど別の手段をとるかになる。
pthreadで統一するのも悪くはないが、あまりSDL以外のライブラリに依存するとSDLを使う意義が薄れる。
もし3,4行の修正でSDL_Threadが動くならその方が楽なのだが。アラインメントの問題だけだし。
そもそもalignasした変数をスタックに置く時にどういった処理をしているんだろう。
SDL_CreateThreadの子スレッド経由でThreadFuncを呼ぶとずれるが、親スレッドから直接呼べばズレない。
構造体のサイズはalignasの時点で揃えられてしまうんだろうけどメモリのオフセットは実行時に決めている?
SDL_CreateThreadの子スレッド経由でThreadFuncを呼ぶとずれるが、親スレッドから直接呼べばズレない。
構造体のサイズはalignasの時点で揃えられてしまうんだろうけどメモリのオフセットは実行時に決めている?
追記)原因は
結論から言えばSDLにバグがあるわけではなく、スタックアラインメントの問題。
gccは速度のためにスタックポインタのアラインメントをデフォルトで16byteに合わせているのだが
当然その調整にメモリを余計に食ってしまうので任意でアラインメントサイズを変更できる。
それがgccの-mpreferred-stack-boundary=N (Nは2の乗数倍を表し、N>=2とする)オプションだ。
組み込み用途なんかで速度よりメモリを節約したい場合は2を指定し、そうでないならデフォルト(=4)やそれ以上に設定する。
当然その調整にメモリを余計に食ってしまうので任意でアラインメントサイズを変更できる。
それがgccの-mpreferred-stack-boundary=N (Nは2の乗数倍を表し、N>=2とする)オプションだ。
組み込み用途なんかで速度よりメモリを節約したい場合は2を指定し、そうでないならデフォルト(=4)やそれ以上に設定する。
で、注意しなければならないのは
Nが小さい設定でコンパイルされたルーチンからNが大きい設定のルーチンを呼ぶとアラインメントがずれたままになる
大変重要な事なのでもう一度言う。
Nが小さいルーチンからNが大きいルーチンを読んではいけない
どうしてか?と聞かれても当方gccに詳しくないのでわからんとしか言えないが
gccのリファレンス
ページ中盤
To ensure proper alignment of this values on the stack, the stack boundary must be as aligned as that required by any value〜〜〜 の辺りに書いてある。
gccのリファレンス
ページ中盤
To ensure proper alignment of this values on the stack, the stack boundary must be as aligned as that required by any value〜〜〜 の辺りに書いてある。
対策
SDLのライブラリは既存のバイナリを使うとNが2なので不具合が起こる。従って自分でビルドする
とはいえ何も難しいことはなく、何時ものように
./configure --host=i686-w64-mingw32 (...あと適当にオプション)
と打ち、Makefileを作ったらおもむろにテキストエディタで開き
とはいえ何も難しいことはなく、何時ものように
./configure --host=i686-w64-mingw32 (...あと適当にオプション)
と打ち、Makefileを作ったらおもむろにテキストエディタで開き
EXTRA_CFLAGS = -Iinclude -I../include -mmmx -m3dnow -msse -mpreferred-stack-boundary=2 -Wall
となっている行のmpreferred-stack-boundaryの項目を消しておく。
後は普通にmakeすればOK。
後は普通にmakeすればOK。