シェーダーのコンパイル失敗時挙動


どうもglGetShaderInfoLogの挙動がおかしい。
シェーダーのコンパイル失敗という挙動を示すようになったのも問題だったりするけど、
この関数の挙動が赤本のサンプルプログラムでは正常動作しない。

原因の推測

このおかしな挙動を始めた前後で変えたことはCatalystのバージョンを変えたこと。
現在は 10.7 を使っている。

そもそも以前の環境ではGLSLのリンクまでうまく動作していた。
ドライバが持つコンパイラ&リンカの挙動が変わったとしか思えない。

症状

あるプログラムのGLSLのコンパイルが失敗するようになった。
そしてエラー処理に突入し、赤本に書いてあるようなコードでエラーログを出しているが、
関数を抜けるとアクセス違反で終了する。

デバッグ

  • NVIDIA環境では旧コードで問題なく動いていた。
  • ATIのドライバ更新する前までは問題なく動いていた。

これらの点から考えると、プログラムの大筋は間違ってはいない。
今回のドライバによるバグが原因と考えられる。

エラー発生ポイントから、glGetShaderInfoLogのログを取得して、解放する部分で何かあるとしか考えられない。

  1. glGetShaderivでログ長取得
  2. ログ格納バッファ確保
  3. glGetShaderInfoLogでログを取得
  4. ログ表示
  5. 格納バッファ解放
  6. 呼び出し元に失敗コードを返却し、処理抜ける

という感じにくんでいるが、ログ格納バッファを解放する段階でアクセス違反していることが判明した。

CRTの中を追いかけていってわかったのは、格納バッファにログを取得した時点で、
メモリ領域を一部破壊しているということだった。
どうもログ長で返された値よりも大きなサイズを書き込みしている模様。
また、glGetShaderInfoLogで取得できるログバッファ書き込みサイズもまたglGetShaderivで返されるログ長と同じなので当てにならない。

末尾にヌル文字でも余計に書き込んでいるのでは?と考え、
取得できるログ長にその分を加算して確保するように変更した。
その結果、このアクセス違反問題は解決した。

結論

OpenGLはドライバ依存になる部分がおおい。
値を信用せず、若干の余裕を持たせてバッファは確保しておく方が
多くの環境で動かすポイントになりそう。

また、NVIDIAだけでなくATIのカードでも動作を試してみることが
OpenGLに至っては必須なのかもしれない。
DirectXだったら両者でそこまで深刻な違いは出ないのかもしれないが。

スポンサーリンク

シェアする

  • このエントリーをはてなブックマークに追加

フォローする