GL拡張のリスト(2)

ドライバを更新して取得してみた。

  • catalyst 10.7

感想

transfrom_feedback2,transform_feedback3がサポートに入っている!
GL_ARB_sampler_objectsもサポート範囲に入っているし、
OpenGL4.0には対応しているってことだろうか。

気になった点

dxt6,7の拡張が消えた!
その代わり、BC6,7用拡張であるGL_EXT_texture_compression_bptcが含まれた模様。
こちらについては、OpenGL Registryに登録があるし、
きっと正しいのだと思う。


続・CubeMapGS

以前の7/29日記で、CubeMapGSの動作を書いたので、
NVIDIAのGeforce9800GTではどうだったんだろうと思ってチェックしてみた。

球体モデルの結果

カード Instancing fps値
RADEON 5450 TRUE 28.2
RADEON 5450 FALSE 38.2
GeForce9800GT TRUE 119.2
GeForce9800GT FALSE 61.2

これだけ見ると世代的には前の9800GTのほうが性能がいい。
またインスタンシングフラグの影響がそれぞれ逆転しているのも不思議。

車体モデルの結果

カード Instancing fps値
RADEON 5450 TRUE 8.8
RADEON 5450 FALSE 9.7
GeForce9800GT TRUE 44.8
GeForce9800GT FALSE 32.6

製品のレンジが違うとはいえ、ここまで差があるのか。
GSはNVIDIAの圧勝です。

まとめ

この状況を見るとGSで6面のキューブマップについては
リアルタイムに毎フレーム処理できるものではなさそうです。
せいぜいシーン初回で描いてしまうとかその程度かなと思います。
他のメリットは、レンダーパスの処理がシンプルになるというのもあるけど、
ローエンドでもこれくらいの形状ならある程度(60fps維持)の性能が出せないと、
安心して使えないですね。


DirectX10を始めました

はじめに

今はもうDirectX11が出て使われ始めていますが、
今更DirectX10の勉強を始めてみました。

今回初ということで、画面のクリアをするプログラムを作ってみました。
これをベースにしていろいろと機能を触ってみようかと思います。

DXGIのセットアップ

DXGIとはスワップチェインとか管理しているレイヤーになります。
ハードウェアデバイス列挙やフルスクリーンへの切り替えなど担当してくれます。
まずはこの初期化を行います。
初期化すると、スワップチェインとD3D10デバイスが取得できます。

やり方は以下の通りです。

初期化に必要なパラメータを構造体に詰めて、D3D10CreateDeviceAndSwapChainを呼び出します。
D3D9の頃と比べるとこの部分は楽になったような気がします。

バックバッファの取得とメインとなるカラーバッファの取得

デバイス生成するとバックバッファが1つ付いてきます。
これを通常の描画先とするために、ビュー(RenderTargetView)を取得します。
その取得している部分は以下のようになります。

バックバッファは2次元テクスチャの扱いで、
この中身にアクセスするためのビューと作成しています。
普段のクリアで使うのは、ビューを用いて行うので、
作成が終わったらpBackBufferは使わないため解放しています。

デプスバッファとステンシルバッファ

カラーのバッファについては標準で付いてきたのですが、
デプスは自分で作らないといけないようです。

デプスとステンシルについては扱い的に2Dテクスチャとなっているようで
まずはこれの作成から開始します。
このテクスチャを作った後はバックバッファと同じようにビューを作成します。

ビューポートの設定と標準の描画先の設定

若干構造体が変わっていますがD3D9のころと中身は変わりません。
ここで先ほど作成した2つのビューをデバイスに設定しておきます。

画面のクリア処理

クリア処理は、デバイスに対して行うという感じではなく、
デバイスに対して、クリアするビューを設定して行う、という感じになっています。

メインのループでこの記述をすれば画面のクリアが行われ、
今回赤い色が表示されます。

後始末

今まで取得した&作成したインターフェースに対して、
Releaseを呼び出していきます。

感想

画面のクリアまでならば、D3D9の頃と比べて遙かに楽でした。
若干概念が変わっている部分については最初こそ戸惑いましたが、
そういうものだと理解してしまえば引っかかるような場所でもありません。

ビューとは、バイナリデータを解釈するものである、と自分は理解しました。
このバイナリデータというものがテクスチャであり、リソース群を示します。
よって、解釈対象であるビューに対してクリアなどの操作指示を行うのだと。

この2段構えな感じがD3D10の特徴なのかもしれないと思います。
そしてこのせいでD3D9ほど素直な感じがしないのだとも感じます。

ソースコード

適当に書いた初回D3D10のソースコードです。
自動生成されるコードに今まで説明した部分付け加えて、
そして、描画ループがまわるようにした程度の簡単なものです。

HelloDX10ソースコード

何かの役に立つかな・・・


テクスチャオブジェクトとサンプラ設定

いつのまにか、OpenGLのテクスチャ挙動もDirectXに合わせる方向になっているようだ。OpenGL 3.0では、glTexParameteriで GL_TEXTURE_BORDER_COLOR を設定することが非推奨となっている。
他にも テクスチャラッピングモードで GL_CLAMP_TO_BORDER を指定することは推奨されていないとなっている。
さらにglTexImage2Dでボーダー指定で 0 を設定することを要求しているようです。

従来のボーダーの処理に関して、実はドライバ内部のソフトウェア処理にて実現し、
ハードウェアとしてはサポートしていない!ということになっているのでは?と疑いを持ったのですが、
そういうわけではないようです。

DirectX10のAPIを調べてみると、ボーダーの色設定はできるのでボーダー自身のサポートがなくなるわけではないようです。
では、OpenGLではどうなるのか調べてみたところ、サンプラーオブジェクトなるものが存在していました。
そのエクステンションの名前は、”GL_ARB_sampler_objects”。
ただし、OpenGL 3.3での拡張となるようです。

サンプラオブジェクトを作成し、テクスチャのバインド前にセットすることで、
拡大縮小フィルタ設定、テクスチャラッピングモード、ボーダーカラーの設定らが可能になるとのこと。
まさにこの挙動はDirectX10のサンプラーオブジェクトと同じだといえます。

残念ながら手元のRADEON環境ではOpenGL3.3対応していないのか、
GL_ARB_sampler_objects の文字列が見当たらなかったので試せていません。
Catalystの更新((10.5で含まれるらしい。また以前のtransform_feedback2,3もここで入るらしい)でサポートされるとのことなので、そのうち試してみようと思ってはいます。


GL拡張のリスト

うちのRADEON 5450のGL extensionのリスト

OpenGL 4.1サポートされるドライバが公開されたら更新したい。
さっさとでてくれないかなと期待してます。

catalystのバージョン: 8.681
Direct3Dバージョン: 8.14.10.0716
OpenGLバージョン: 6.14.10.9232

GL_AMD_texture_compression_dxt6は BC6形式のサポートで、
GL_AMD_texture_compression_dxt7は BC7形式のサポートってことだろうか。

一方、よくわからないのがキューブマップの部分。

  • GL_AMD_seamless_cubemap_per_texture
  • GL_ARB_seamless_cube_map

どちらもキューブマップのつなぎ目をきれいにする拡張の模様。
単純に標準化したときに(ARBに加わったときに)名前が変わっただけなのかな…。


OpenGLでのストリームアウト その5

AMD(ATI)で動くOpenGLのストリームアウト(transform_feedback拡張)が一応できました。GL_EXT_transform_feedback のエクステンションを利用します。

準備するもの

  • 頂点データのためにVBOを使えるようにすること
  • GLSLによるシェーダーを使えるようにすること
  • クエリー発行できること

シェーダーの準備

GLSLシェーダーを準備します。
glAttachでオブジェクトを設定し、glLinkProgramまで終わらせておきます。

その後そのシェーダーからストリームアウトするのに必要なvarying変数を設定します。
変数名による配列を準備して、
それをglTransformFeedbackVaryingsEXTにて設定します。
この例を下記に示します。

ストリームアウト実行部

シェーダーをセットするほか、いくつかの設定を行います。

ストリームアウトするため、ラスタライズ処理の無効化をします。
また、書き出す先のVBOをバインドしておきます(streamOutIdが対象VBOです)。
続いて、ストリームアウトの開始を宣言し、同時に書き込んだプリミティブ数を取得するためのクエリを発行しておきます。

この後、通常の描画と同じように実行します。
終了時には設定を戻します。以下に例を示します。

各種終了を宣言し、クエリの結果を取得します。
ここでプリミティブの数を取得しないとその後結果をうまく使うことができません。
OpenGLにはDrawAutoは存在しないためです*1

この後描画するのであれば、GL_ARRAY_BUFFERにバインドして通常と同じように描画できます。
ただし、インデックスバッファと併用できるかは現在未確認です。
頂点の増減がGSで行われてしまうため(行われる可能性があるため)です。
頂点を増やさなかったら、インデックスバッファ使える可能性はあるのかも。

*1 : transform_feedback2拡張らで含まれるらしいですが

NVIDIAで使えない理由

glBindBufferOffsetEXT のAPIだけが取得できません。
取得しようとするとNULLが返ってきます。
そのため、同様の機能を探すとglBindBufferOffsetNVとなるため、
それだったらNV拡張のほうを使うか、ということになるわけです。

多くの部分でEXTと共通ですが、ストリームアウトするvarying変数らの設定が異なります。
NVIDIA版では、変数のLocationIdで設定するようになります。

感想

とりあえずNVIDIAの今後のドライバでこのAPI取得ができるようになるなら、
どの環境であれEXT拡張に統一できるんですが・・・。
また、一部のAPIが欠落しているのにもかかわらず、GetString( EXTENSION )でサポートしている旨を返してきてほしくはないですね。


OpenGLでVRAM情報を得る – AMD編

最近気づいたけど、AMD(ATI)用のエクステンションで
GL_ATI_meminfo というものがある。
これを用いれば、OpenGL環境のアプリでもどのくらいVRAMを使っているかがわかる。使い方は簡単で、以下のようにして値をとってくる。

ここで GL_VBO_FREE_MEMORY_ATIの代わりに以下のものを使うこともできる。

  • GL_TEXTURE_FREE_MEMORY_ATI
  • GL_RENDERBUFFER_FREE_MEMORY_ATI

種別に応じて使用可能な領域サイズを KB単位で知ることができる。
しかしながら、手元で試してみたところどの種別にしても同じサイズが返ってきた。
多くの場合、VBOかTEXTUREで返ってくる値のみをみていればいいのかもしれない。

その一方で、搭載メモリを取得する方法も発見した。
こちらは定義されていないので自分でdefineなどをしてあげる必要がある。
なおこれもKB単位で返ってくる。

これらの結果を利用すれば、搭載メモリ、使用メモリ、空きメモリを
OpenGLの環境であっても計測することができる。


CubeMapGS

DirectXサンプルにある、CubeMapGSを動かしてみた。
Radeon5450では実用的な速度で動いているとは言い難い。

  • Sphereで 25fps程度
  • Carで 10fps程度

DX11世代のハードでこの状況だとまだ安心して
毎フレーム描画で使えないなと思う。
せいぜいシーンの切り替わりタイミングで1回だけとかになるだろうか。

でもそれくらいだったら6回パスを回してもいいんじゃないかとも思える。

このスペックのせいでOpenGL側で同じように処理する機能はどうやるかっていう
調査のやる気がずいぶん削がれてしまった・・・


STL関連リンクエラー

どこかで以下のようなエラーを見かけたので、
それについて書いておこうと思います。

メッセージ例

error LNK2019: 未解決の外部シンボル “__declspec(dllimport) class std::basic_ostream > &
__cdecl std::operator<< >(
class std::basic_ostream > &,char const *)” (__imp_??$?6DU?$char_traits@D@std@@@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@0@AAV10@PBD@Z)
が関数 “hogehoge(void)” で参照されました。

原因

libを作った環境でのSTL実装と、exeを作ろうとした環境でのSTL実装が違うためにこの問題は起こります。
最近の例だとVisualStudio2005とVisualStudio2008の混在させて使うような状況で起こりえます。

この例でいえば、VCランタイムはDLL版を使っています。
かといってVCランタイムのスタティック版を使ったからといってこの問題は解決できません。
そのときには、”○○は未解決です”というリンクエラーが出ることになるでしょう。

解決策

使用するlibとexeとでコンパイラのバージョンを一致させる。
もし、一方がビルド不能なのであれば、そちらにあわせることになるでしょう。

感想

こういうことがあるからあまりSTLって使いたくないんですよね。
長い間使いたいようなlibを作る場合には、特に。


OpenGLでのストリームアウト その4

今までのものは GL_transform_feedback_NVのやつでやっていた。
しかし、今回AMDのRadeon 5450環境を手に入れられたのでこちらについても
ちょっと試してみた。GL_transform_feedback_EXT をサポートしているようなのでこちらを使うことになりそう。

APIの置き換え(その1)

NVIDIA AMD
glBeginTransformFeedbackNV glBeginTransformFeedbackEXT
glEndTransformFeedbackNV glEndTransformFeedbackEXT

こんな感じで単純に置き換えておけば、NV->EXT使用になる

APIの置き換え(その2)

glTransformFeedbackVaryingsNV は glTransformFeedbackVaryingsEXT を使用することに。
中身が違うので単純に置き換えてはいけない。

以前 ”GLchar**を受け取る!?ヘッダ正しいですか?”と書いていた部分が間違っていたことに気づいた。

  • EXT版ではGLchar**を受け取る。
  • NV版ではGLintを受け取るべき

という差異があった。これが仕様。

EXT版では、varying変数名を設定できるが、
NV版ではvarying変数のロケーションIdを受け取る
という仕様の違いがあったためであった。

NVIDIAとAMDと両方のデバイスをさわってみて初めて納得がいった。

感想

やっぱりOpenGLのTransform Feedback(StreamOut機能相当)は情報が少ない。
使っている人が少ないのかもしれないので、これからがんばる人のために
ここに情報を書いておきます。

近いうちにNVIDIAとAMDと両方で動くtransform_feedbackのサンプルを作って公開する予定です。