OpenGL一覧

Windows10 で OpenGL 使えるのか?

Windows10 の正式なリリースが間もなくとなってきました。この Windows10 で DirectX 12 が使えるようになるというのは、各所で語られていて有名な話ですが、それと対を成す OpenGL は生きてるんだろうかと思って、まずは軽く調べてみました。

opengl-capture-win10

軽くといいつつ、デュアルディスプレイでそれぞれにフルスクリーンとなる OpenGL アプリケーションを動かしてみました。上記の図は その時の様子を PrintScreen でキャプチャしたものです。本来は同じクリアカラーおよび同じような位置で三角形を書いているのですが、なんかおかしなことになっています。実際のモニターでは2つの画面でこのようなズレはないので、不思議なところです。
ちなみに、2つのディスプレイ解像度が違うため、アスペクト比がずれているので全く同じ絵にはなりません。

このときの OpenGL コンテキストの情報を出してみるとこんな感じでした。

今のドライバだと NVIDIA で OpenGL 4.5 が使用可能なようです。ドライバが入っていなくて、OpenGL のエミュレーションというかリファレンスドライバで動く、なんて状況ではなさそうです。

まとめ

とりあえず NVIDIA ドライバでは OpenGL はそのまま使えそうです。他の AMD や Intel のほうで DirectX12 & OpenGL が両方サポートされるかどうかは、徐々に調べてみようと思います。
それと、 PrintScreen ってこんな挙動だっけと不思議な部分があるので、Windows7, 8.1 あたりで同じだったかも調査してみたいと思います。

その他

OpenGL でフルスクリーンは調べるとよく出てくるのですが、そこ止まりで、複数ディスプレイで OpenGL をやっている例を見かけませんでした。相当マイナーな部分なのでしょうか。こうも事例が見つからないと、たまたま動いているだけ感を感じます。


BC7について段階的にデコードしてみた

BC7のCPUデコーダーを作っている過程でおもしろいものが確認できたので記事にしてみました。当たり前の話ではあるのですが、視覚化されたケースって無いようなので。
BC7 はいわゆる第2世代のテクスチャ圧縮技術で、各ブロックごとに最適なモードを選択してデータを圧縮しています。このブロックがどんな風に割り当てられているかを、ブロックごとの色分けで塗ってみたら以下のような結果を得られました。

image_partition

この段階でも各ブロックの特徴によってモード選択されているのが確認できます。そのためおおよその画像の検討が付く程度にはなっています。これらのブロック種別を順番に展開してみます。 続きを読む


ASTCの圧縮ノイズを調べてみた

今回は期待のASTC圧縮のノイズを調べてみました。

ASTCについて

詳しいことは各所のサイトで触れられていますのでここでは簡単に。 Adaptive Scalable Texture Compression の略で、ARM が開発しました。DXTCがS3の特許関係で色々とあったためか、 ASTC はロイヤリティフリーなことも取り上げられています。
基本的には他の現世代のテクスチャ圧縮と同じくブロックごとのモードを多数持っていることが特徴です。ASTC 固有の特徴は、なんといってもブロックサイズの変更ができるということではないかと思います。

実験

ASTCではブロックサイズを変更することができ、許容できる範囲で BPP を落として削減することができます。試行錯誤の余地があるといえます。
ここでは BC7 や PVRTC への対抗と考えて、それと同じレベルの BPP でチェックをしてみたいと思います。

圧縮のためのツールとしては Mali Texture Compression Tool を用いています。圧縮品質としては最大の品質レベルを選択してデータを作成しました。

ASTC 8BPP(4×4)での結果

8BPPとなるように 4×4 ブロックで圧縮を行いました。この場合は以下のような結果となりました。次の規格レベルだけあって予想通り綺麗に圧縮できていると思われます。左右に並べたくらいではちょっとわかりません。

compare_std_astc_sample01

compare_std_astc_sample02

ツールのほうでは圧縮前後でノイズ具合も表示できるのでこちらの画像も掲載しておきます。
ノイズは割と控えめな感じかと思われます。 [続きを読む]


ETC2の圧縮ノイズを調べてみた

今回は OpenGL ES 3.0 以降で使えるようになった ETC2 について試してみました。アルファチャンネル入りでの圧縮形式として標準的に使えるようになった形式です。基本的な実装方針は ETC1 の拡張したイメージになっています。

データの作成は Mali Texture Compression Tool を用いて行っています。品質は最高品質を選んでいますが、待てないほどではないにしろ割と時間がかかるかなという印象です。その分画質はどうなっているか確認してみたいと思います。

左がオリジナル、右が ETC2 圧縮したものですがどうでしょうか。違いはぱっと見た感じでわかるでしょうか?

compare-etc2-sample01
compare-etc2-sample02

個人的には ETC1 のころと違ってよく綺麗に圧縮できているのではないかと思っています。そこで今度はこれらの一部分を拡大して確認してみたいと思います。 続きを読む


PVRTC2の圧縮ノイズを調べてみた

今回は PVRTC2 の圧縮について、どのくらいの劣化が起こるのかを調べてみました。 PVRTC2 って有名なようでイマイチな感じで、これを検索キーワードにしても PVRTC1 の 2BPP モードがヒットする感じです。 PVRTC-I, PVRTC-II という表記の方がいいのかもしれませんが、 imgtec のブログでは PVRTC, PVRTC2 という記述をされているようです。

PVRTC2について

PVRTC2 は PVRTC をさらに拡張した形式となっています。基本的なブロックフォーマットはそのままに、ブロックごとの2色を記している最上位ビットに別の意味を持たせた感じにしています。それぞれに Opaque なビットは不要、他方から判定すればよし!というのは納得がいきます。
この別の意味を付与されたビットを HardBit と呼んでいます。これにより最近流行のブロックのモードを追加するということを実現しており、追加されたモードは Non-interpolated(非補間), Local palette(ローカルパレット) モードの2種類となっています。これらの仕組みから PVRTC2 は画質の向上のために用意されているようです。

参考: PVRTC,PVRTC2についての Imagination Technologies のブログ

実験

以前の BC7 のノイズ検証でも使ったデータを利用して確認してみます。PVRTC2 データの作成ついては、今のところ PVRTexTool で行えます。
このツールは前後でのノイズ(エラー)も表示させることが可能なため、以前のように別アプリで処理しなくても簡単に確認できます。ここではそのスクリーンショットを載せることで見ていきたいと思います。
注意事項としては、 BC7 と PVRTC2 を単純に比較してはいけないということです。お気づきかと思いますが、 BC7 は 8bit per pixel(BPP) であり、 PVRTC2 は 4BPP であるということです。つまり PVRTC2 が BC7 よりも2倍圧縮率が高いということで、すなわち BC7 より見た目が悪くても当然ということです。

pvrtc2-noise-sample01

pvrtc2-noise-sample02

よく言われていることではありますが、PVRTC系はアルファチャンネルも持たせられるがその場合カラーの品質が落ちる、というのが今回も健在のようです。最初の例ではアルファ抜きの部分にもノイズがありますし、アルファが変化するブロックにあるカラーブロックがひどいノイズとなっています。
アルファ不要のケースにおいてはノイズは階調が変わる輪郭部分に大きく発生していますが、等倍の目視ではあまり感じられないかと思います。 続きを読む


BC7の圧縮ノイズについて調べてみた

優秀だという BC7 圧縮の品質がどんなものか調べてみました。
そのためにはそこそこの品質以上の画像データが必要だったので友人に協力してもらい画像を使わせてもらっています。
この場を借りてお礼申し上げます。

BC7への圧縮については Codeplex からダウンロードできる Microsoft の TexConv を使用しています。この最高品質となる CPU で処理した結果ではなく、 GPU を用いた速度とのバランスがとれているであろうモードを選択しています。

比較

いきなりですが圧縮前後の画像を比較してみます。
左が圧縮前、右が圧縮後のデータです。圧縮ノイズなどは確認できるでしょうか?自分では等倍でぱっと見た感じわかりませんでした。心持ち髪の毛曲線部とアルファの部分でノイズが気になるかも程度です。
compare_std_bc7_sample01
compare_std_bc7_sample02

続きを読む


OpenGLでBC7テクスチャ圧縮を使う

今回は今までにやっていそうでやっていなかった OpenGL で圧縮テクスチャを使用する方法です。
基本的には、定番のDXT1,DXT3,DXT5 などの形式をロードする方法と全く同じなのですが、意外と誰もBC6H, BC7 で書いていなかったため、情報として残しておこうと思った次第です。

BC7テクスチャ圧縮について

詳しいことは他のサイトにお任せしますが、BC7はアルファチャンネル付きでも見た目の情報劣化が少ないテクスチャ圧縮形式です。従来はこの領域では DXT5 が使用されましたが、DXT5 は意外と汚いという認識があるようです。BC7はこの点を改善していますが、今のところ圧縮時間がそれなりにかかるのが懸念点となっています。
とはいっても、GPUの支援を使い一定レベルの変換は割と早くできますし、今となっては問題も少ないんじゃないでしょうか

BC7テクスチャをどう作るか

テクスチャを使用するプログラムは難しくないのですが、データを作成するところが現時点では問題になるかと思います。
いくつか方法はあるのですが、ここではマイクロソフトの公開している方法を紹介したいと思います。

DirectXTex プロジェクト一式をダウンロードすると、その中に TexConv というプロジェクトが含まれています。これをVisualStudio で開いて、ビルドするとコマンドラインツールとしての TexConv ができあがります。

詳しいオプションはツールのヘルプを見てほしいのですが、大体以下のような感じで使えます。入力フォーマットもそこそこ対応しているようです。

通常だとGPUが支援として使える状況であればそちらを使うようで、 -nogpu というオプションをつけるとフルにCPUで演算するモードとなります。
どのくらい重い処理なのか一度試してみるのもおもしろいと思います。2048×2048 なデータで試してみると15~20分くらい返ってこなかった気がします・・・。

BC7 形式で dds 出力すると従来の DDS と違い、DX10 用のヘッダも格納されている点に注意して、ロードプログラムを作成します。

プログラム

ロードする際の肝は、従来と変わらずの glCompressedTexImage2D 関数を使用します。気をつけるポイントは前に述べたデータ開始位置が異なることでしょうか。
DDSを識別するマジックナンバー、DDSヘッダ、DX10ヘッダ の分を先頭からずらした位置が BC7データの開始位置となります。

コード例としてはこんな感じになりました。
BC7 をロードする際には、 GL_COMPRESSED_RGBA_BPTC_UNORM_ARB をフォーマットとして設定して glCompressedImage を呼び出します。また本来ならば、DDSのヘッダから画像解像度を取り出して使うべきですが、手抜きして直接 256×256 を指定してしまっています。

OpenGL-BC7

補足

BC6Hの場合には、GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB, GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB を指定します。
また、BC7のSRGBが要求されるときには、GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB を使用します。
それ以外はロードの方法に変更はありません。


DirectX9 on Windows 7 でメモリの消費調査

今回は DirectX 9.0 を用いた場合ではどんな感じになるのかを調べてみました。環境は Windows 7 (x64) です。また DirectX 9.0 と表記していますが、実際のところは DirectX 9.0 EX のことを指すものとします。

Windows XP までの頃は VRAM の仮想化というものがなく、デバイスロスト発生のためのケアが必要になっていました。その代わり VRAM にデータを送ってしまい、メインメモリは消費しないということができたように思います。(もしかするとできていなかったのかもしれませんが、今更検証価値も低そうなので手元でテストしていないです・・・。)
一方で Windows 7 になってVRAM仮想化が導入され、VRAMの空き容量など取得が難しくなってきました。 DirectX 9.0 は動くものの、その挙動は XP のころとはまた違ったものになっていると予想されます。それなのに検証をしていないままだったので、 VRAMの情報取得という武器ができた今、調べてみようと思ったわけです。

NVIDIA (Geforce9800) の場合

安定状態になってから頂点バッファ 32MB を D3DPOOL_DEFAULT にて作成しました.

状態 メモリ(MB) Dedicate(MB) 共有メモリ(MB)
定常状態 1054.6 47 13
VertexBuffer作成 1回目 1086.7 80 13
VertexBuffer作成 2回目 1119.3 112 13

どの場合においてもメインメモリ 32MB 程度消費し、Dedicate のメモリ 32MB ほど消費している結果となりました。

AMD (RADEON) の場合

状態 メモリ(MB) Dedicate(MB) 共有メモリ(MB)
定常状態 1028.9 45 22
VertexBuffer作成 1回目 1061.1 77 22
VertexBuffer作成 2回目 1093.8 109 22

こちらの場合においてもメインメモリ 32MB 程度消費し、Dedicate のメモリ 32MB ほど消費している結果となりました。

実験その2

描画フレームを回しながら、 100 フレームごとに頂点バッファを確保し描画するという定番のプログラムで実験してみました。
上記の消費メモリが永続的なものではなくテンポラリ扱いならば、相当の数のバッファが作れるはずです。

しかし予想外の結果になりました。

メインメモリの消費が、自分のプロセスに対して発生していました。どうやら D3DPOOL_DEFAULT では自プロセスのどこかにバックアップのバッファが存在するようです。

GTX 750Ti 2GB の状態で普通の 32bit アプリケーションで実行の場合には、x64環境といえども、 1プロセスで使えるサイズは 2GB まで。そのため VRAM 使用量が 1GB 程度のところで DirectX がバッファの作成に失敗しました、とエラーを出しました。このときのプロセスの状況を調べてみましたが、消費されている仮想アドレスが 2GB 近かったです。
 一方で、 32bit アプリで LAA オプションをつけて再実行してみると、今度は VRAM 使用量は 1.7GB 程度にまでなり、プロセスの仮想アドレス使用量は 4GB 近くにまでなっていました。

※ このプロセス内での状況を知るのに VMMap というツールは便利です。

まとめ

DirectX 9.0 の場合においては NVIDIA も AMD も同じような挙動となることを確認できました。またどちらの場合においても使用するリソース分、メインメモリも消費していることが確認できました。これはこれで挙動把握さえできてしまえば、扱いやすそうです。
ただ注意が必要であると感じたのが、自分のプロセスの仮想アドレス空間にバックアップ先を確保するため、メモリ不足よりも自身の仮想アドレス空間を枯渇させてしまうのが早そうに思います。 64bit 環境を必須とするなら 32bit アプリケーションの場合、 LAA 必須といってもいいレベルだと思いました。
 この場合、よいビデオボードを使っていて 「 4GB の VRAM 全部使いきる DirectX 9.0 アプリケーションを開発してやるぞ。 ただし 32bit アプリケーションだけどなっ」 という夢はかなわないことが判明しました。そんな人は少数派だとは思いますが・・・。


OpenGLでOut of memory とメモリの関係 (AMD)

今まで NVIDIA のもので調べていたので今回は同じプログラムを AMD Radeon 5450 を使ってデータ取得してみました。

  • Windows 7 x64 (2GB)
  • AMD Radeon HD 5450 (1GB)
  • ドライバは Catalyst Omega 14.12

プログラムは OpenGL を用いて 32MB 単位で頂点バッファを 300 フレーム間隔で確保していくものです。作成後、 Out of memory のエラーが返ってきたら終了します。

実験結果

何度か動かしてみましたが、 GL_OUT_OF_MEMORY のエラーが取得できませんでした。あふれた状態になったと思われるときには、アプリケーションがフリーズ状態に陥りました。 SwapBuffers の実行内部で無限ループしているような気配でした。
 この状況になるまでのデータで、システムの使用メモリ、 VRAM の使用量、共有メモリの使用量をグラフ化してみたものが以下のようになります。 NVIDIA の場合とは傾向が違っていておもしろいです。

radeon_ogl_outofmemory_log
今回の場合は、 VRAM に配置できる場合にはそちらに配置して、システムのメモリは消費しないようにみえます。実際にこのタイミングではプライベートヒープが増えているような感じではありませんでした。 観測タイミング次第によっては glBufferData の中身のテンポラリの DMA 転送タイミングで作業バッファぽいものが見えたりしますが、数フレーム後解放されたりしました。 VRAM に配置できない状況になったときに、初めてシステムのメモリを消費しての共有メモリ使用増加が観測できました。おおよそ 1.6GB ほどの使用量になったときにアプリケーションがフリーズ状態に陥ったように見えます。この環境ではビデオアダプタのプロパティで確認できたのが「利用可能な全グラフィックスメモリ 1791MB」とあり、最大値であるこの値にまで到達したのかなと思っています。

感想

AMD のグラフィックスドライバは余計な(?)システムメモリを消費しなかったので、 OpenGL 実装でも無駄はないという点に関心しました。一方で、メモリあふれのエラーを検知できないのはマズイですね。無駄なメモリは確保しないから、溢れさせないよう気をつけてアプリケーションを実装しましょう、ということでしょうか。

おまけ

同じようなテストを Windows8 (64bit) に切り替えて行ってみました。おおよそ同じ傾向になりました。ただシステムメモリの細かな変動が観測され、作業メモリとして使用している部分がみえたのかなと思っています。(これは以前に glBufferData 直後での内部動作でそのような動きを見せたためです。)
ドライバが標準的に導入されたものを使用し、 Catalyst Omega ではない点ももしかすると影響しているかもしれません。
radeon_ogl_outofmemory_log_win8


OpenGL @NVIDIAでのメモリ調査

NVIDIA Geforce で OpenGL を使った場合のシステムメモリの消費について調べてみましたが、サイズ可変でどのくらい消費量が変わるのか、というものでした。また API 実行の各タイミングで計測したのみで、時間経過を考慮していませんでした。

今回はサイズは固定し、 100 フレームに 1 回頂点バッファを確保して描画するという方法を試してみました。また描画に使用されない場合は処理をされないという可能性を除外するため、次フレーム以降は確保したバッファを用いての描画を行うようにしています。

確保のタイミングで、以前の確保時のデータとどのくらいメモリ使用量が変動するかをグラフ化したものが以下となります。
nvidia_opengl_temporary

結果

NVIDIA の場合、 OpenGL の作業用のメモリとして多めのメモリを使用する傾向にあるようです。しかしフレームの経過とともにその作業メモリを解放も行っているようです(そうでないと差分デルタが減った説明ができない)
多くの場合は、 VRAM 側に確保したメモリサイズと同じ程度のメモリを消費すると考えて良さそうです。