「 DirectX 」一覧

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 アプリケーションだけどなっ」 という夢はかなわないことが判明しました。そんな人は少数派だとは思いますが・・・。


DirectX11の場合のシステムメモリとVRAM消費について


今までは OpenGL の場合を調査してきました。今回は DirectX11の場合を調べてみようと思います。ドライバが一緒ならきっと同じ傾向を示すんじゃないかなと予想して実験をスタートです。

実験

DirectX11のプログラムとして、100フレームごとに頂点バッファ 32MB を確保し、次フレーム以降はこのデータを使って描画するプログラムを作成しました。
各フレームでの各メモリの使用状況を取得して、グラフ化しました。

実験は以下の環境で行いました

  • GTX750Ti Windows 7 347.09
  • RADEON HD 5450 Windows 7
  • RADEON HD 5450 Windows 8

結果

それぞれの実験結果のグラフを以下に示します。

nvidia_memory_graph_dx11_win7

radeon_memoy_graph_dx11_win7

radeon_memoy_graph_dx11_win8

NVIDIA も AMD も同じような挙動を示す結果となりました。また VRAM が使用可能な状態であれば、追加のシステムメモリの消費もなく良好といえそうです。(とはいっても追加のメモリを要求されたのは NVIDIA OpenGL の場合のみでしたが)。さすが仕様が決まっている DirectX といえるかなと思います。
 ちなみに RADEON のほうのグラフ末尾がおかしなことになっていますが、このときアプリは相変わらずフリーズ状態になってしまいました。ですので、システムメモリを VRAM リソースとして使用始めたらやや注意が必要になっていきそうです。ビデオメモリ仮想化が入ったといわれる現時点においても、なるべく搭載量を超えないようにするのはマナーとしておいたほうがよさそうです。


GPUViewを使う前に


GPUViewを使ってみようと思い、Windows Performance Toolkit とかを入れてみたのですが、ログ収集のためのコマンドバッチ log.cmd を実行するとエラーが出ることが確認できました。ちなみにこの症状は WIndows7 64bit 上で確認しています。
 そのエラーというのが、「4000 の使い方が誤っています。」というもので、このメッセージだけではよくわかりません。

これを解決するためには環境変数をセットすると良いようです。log.cmdを実行する前に、以下のようにして値をセットすると実行できるようになりました。

実行した後は、対象アプリケーションなどを実行して、再び log.cmd を実行してログ収集を停止して、その際に出来上がる Merged.etl ファイルを GPUView で開いてあげれば OK です。まだ GPUView の見方がわかっていませんが、これで実行&情報収集は出来るようになったのでよしとします。


XInputの注意事項


最近になってゲームパッドのコーナーを見てみると、純正XBOX 360パッド以外でもたくさんの XINPUTの対応パッドが並んでいることに気付きました。これはXINPUT無視できないなーと感じました。また多くのパッドが DirectInput との切り替えスイッチを持っていて、両対応できるようになっていました。
 これはアプリケーション側も両対応しておいたほうが何かと都合良さそうな感じです。

ひとつ注意事項があります。
VisualStudio 2012など使っていると DirectXSDKが統合されたこともあり、XInputのインクルードやライブラリのリンクについてちょちょいとやってしまえるのですが、ここに罠があります。
 VisualStudio 2012 では標準の対象 OS が Windows8 であることを想定しているため、XInput も Windows8のものをリンクするようになっています(XInput.lib指定時)。これを回避して、Windows7やWindows8で動くようにするためには、リンクするライブラリを “Xinput9_1_0.lib” に変更します。これで Windows7の環境でも動作させることが出来るようになります。ただ古いバージョンになるため使用できるAPIに制限が出来てしまいますので、注意が必要です。

参考: XInput Versions(MSDN)


DirectX11で複数ウィンドウを使ってみる


最近Mach-Oの調査ばっかりやっているので、DirectX11とか触ってるとほっとします。

昨今では2つのディスプレイが繋がっていることも珍しくないと思います。
それぞれに対してDirectXアプリケーションのフルスクリーンやりたいとか、独立した複数ウィンドウでDirectXの描画やりたいとかそういうときにどうしたらよいかを実験してみました。

結論から言えば、複数のデバイスコンテキストを作る必要すら無く、レンダーターゲットビューとスワップチェインを複数持つことでこれらを実現出来ることがわかりました。デバイスが独立ではないのでリソースも共有出来ます。

初期化

DirectX11の初期化部分を説明します。
D3D11CreateDeviceAndSwapChain関数を使用して初期化することは出来ないようで、必要なオブジェクトを順番に作成していく必要があります。まずは D3D11CreateDevice関数でデバイスの初期化、続いて必要な数のスワップチェインの作成となります。
スワップチェインの作成はデバイスから直で出来ず、DXGIのオブジェクトを数回経由する必要があります。

これらの処理をざっくりと以下に示します。

スワップチェインを作成できたら、それぞれのウィンドウ(場合によってはディスプレイ)に対してのバックバッファを作成しておきます。
これはpSwapChain[0]->CreateRenderTargetViewでいつも通りに作成する感じです。必要ならデプスステンシルも作成しておきます。

描画

描画の方は何も難しいことはありません。複数のレンダーターゲットを扱ったことがある人なら意識するような違いがないです。コードを以下に示します。

まとめ

マルチウィンドウにすることでどのくらい2重でデータ持ちしないといけないかと心配しましたが、結構楽に実現出来ることがわかりました。スワップチェインが個別という程度で、他はマルチレンダーターゲットやっているときと変わらない感じです。

今回試してみたプログラムでは以下のようにリソースも1つでそれぞれに描画してみました。

dx11_multi_window


DirectX11でMSAA


DirectX11でMSAA(Multi Sampling Antialias)を試してみました。
検索でよく見つかるのが、プライマリのバッファをMSAA使用する例はよくみかけるのですが、テクスチャレンダリングする場合においてMSAA有効でレンダリングするというサンプルを見つけることはできませんでした。
そんなに難しい話ではないのですが、サンプルプログラムが見つからなかったので今回作成してみました。

まずは結果です。テクスチャを描画先(レンダーターゲット)として三角形を描画しています。その結果をテクスチャとして取得して、四角形のポリゴンに貼り付けて表示しています。
result-msaa

結果を見てもよくわからないので、MSAA OFFの場合の結果を以下に表示します。

msaa-off

これでもよくわからないかもしれません。そこで両者を比較して拡大したものを示してみます。これならば違いがわかるでしょうか?MSAAが有効なものについては、ポリゴン境界がなめらかに見えるように色が補間された結果が見えています。

msaa-comp

手順について

レンダーターゲットとしてテクスチャを使う方法についてはここでは説明しません。
ここではMSAAテクスチャを作成する方法と、それをテクスチャとして使う方法の2つを説明したいと思います。

MSAAテクスチャの生成

描画先となるテクスチャを作成する際に、MSAA用のパラメーターを設定します。
D3D11_TEXTURE2D_DESC 構造体の SampleDesc内のパラメータが該当するのですが、ここにパラメータを指定します。

これらのパラメータの設定がよくわかりませんでしたが、下記に示すように CheckMultisampleQualityLevels から取得できる Quality値を指定しておけばよいようです。

この例だとおそらく 4x の MSAA が有効となるようです。

MSAAテクスチャとして使う

上記の pRenderTargetにたいして描画行われた後でテクスチャとして使用するためにはResolve処理を行わなくてはなりません。またこのときに、Resolve結果格納先として別のテクスチャが必要になります。
普通はこのResolveされたのテクスチャを他の描画で使用します(正確にはこのテクスチャのShaderResourceViewを、ですが)。

まずはそのResolveテクスチャの作成についてはこんな感じになります。

Resolve処理

簡単ですが、D3DDeviceContextについて以下のAPIを呼ぶだけです。

レンダーテクスチャを使う際の注意点といいますかお作法として、
レンダーテクスチャ(RenderTargetViewとして)セットする前に、そのテクスチャがShaderResourceViewとしてセットされていないか確認し、すでにセットされているならば解除しておくことが望ましいようです。
D3Dのデバッグレイヤー有効にするとわかるのですが、シェーダーリソースとして設定されているものをレンダーターゲットとして設定した際に、警告メッセージが表示されます。これはそのシェーダーリソースがシェーダーで使用されていなくても警告がでますので要注意です。

サンプルプログラム

今回のサンプルプログラム全体です。VisualStudio2012で作成しています。
SampleMSAA11サンプルプログラム(Zip)

まとめ

意外と使われないのか、テクスチャに対するMSAAをやってみました。


OpenGLとDirectX11で、あと何が足りてないか


ここ1ヶ月ほどは主に最近のOpenGLについて勉強しているわけですが、DirectX11と比べてまだ何が足りていないかまとめてみます。

やったこと

  • テクスチャ配列 (DX10だけど)
  • ジオメトリシェーダーでストリームアウト&ポイントスプライト (DX10だけど)
  • ハードウェアでのインスタンシング描画
  • テセレーションのシェーダーについて(TCS, TES)
  • シェーダーの実行関数の動的切替(DX11でいうところのDynamic Shader Linkage)
  • インダイレクト描画

まだやれていないこと

  • Texture Buffer (なんかよくわかっていない)
  • コンピュートシェーダー(OpenGL4.3で入った)
  • UAV関連(↑のコンピュートシェーダーの範疇かも)
  • NVIDIA の DirectX と OpenGL の inteop
  • NVIDIA の bindless 色々(GL4.4では標準化されてGL_ARB_bindless_texture).
  • Tiled Resource (DirectX11.2の機能らしい. GLではGL_ARB_sparse_textureだとか)

Draw Indirect 系を調べてみた (OpenGL vs DirectX)


OpenGL では Draw Indirect 系が充実しているとの情報があったので、DirectXとどのように違うのかを調べてみました。

DirectX 11 では、 DrawInstancedIndirect(), DrawIndexedInstancedIndirect() の2つの関数が DrawIndirect系として使用可能です。DirectX10では DrawAuto() という関数が存在して、DirectX11ではこれを汎用化して上記の関数群となったようです。

上記の関数はインデックスバッファ有・無しの違いで分かれているだけで、インスタンス描画を考慮するもののそれ以上の機能は持っていないようです。

一方で OpenGL の Draw Indirect 系は次の関数が用意されています。

  • glDrawArraysIndirect()
  • glDrawElementsIndirect()
  • glMultiDrawArraysIndirect()
  • glMultiDrawElementsIndirect()

ちなみに、glMultiDrawArraysIndirect() は、複数回の glDrawInstancedIndirect() を1回の呼び出しとするようなものです。また glDrawArraysIndirect() が DrawInstancedIndirect() に相当するようです。Indirectのバッファの中には、インスタンス数を指定する項目も含まれるようです。

複数回の描画を束ねられる glMultiDrawArraysIndirect ですが、結局のところ CPU 側に描画数を通知しておく必要があります。そこが何ともうまくないところですが、ARB_indirect_parameters という拡張でこの対策がおこなわれているようです。
 ARB_indirect_parameters では、インスタンス数を格納しておくためのバッファが追加サポートされるようになります。そのバッファが GL_PARAMETER_BUFFER というもので、GLsizei のデータを入れておく入れ物となっています。関数としては、glMultiDrawArraysIndirectCount, glMultiDrawElementsIndirectCount となっています。


VisualStudio 2013をインストールしてみた


MSDNのほうではVisualStudio 2013がRTMになってダウンロード可能となったのでインストールしてみました。
今回はその記録です。

まず素のWindows7にインストールしようとしたら、セットアップできませんでした。
InternetExplorer10 を要求するようです。
DirectX SDKを使って開発している場合にはこれが少々問題になって、IE10インストール後はPiX for Windowsが使用できなくなるようです(詳しくはこちら)。
IE10のインストール後は、VisualStudio2012の付属のツールを使って調査して下さい、ということのようです。
・・・でもこれだとDirectX9が非対応のようで残念なのですが。時代的にもうDirectX9は積極的なサポートのほうは終了という意思の表れのように感じます。

ランタイムで気になった物のバージョンを調べてみました。

  • .NET Framework 4.5.1
  • VCランタイム 12.00.21005.1
  • Windows Kitsフォルダ内には 8.0 と 8.1 の両方のファイルが存在
    • d3dcompilerもそれぞれにあった。d3dcompiler_46/47.dll, d3dcsx_46/47.dll となっていて、これらは再配布可能フォルダにあった。

Windows8 RTMでは .NET Framework 4.5 だったのでわずかに上がってます。Windows7 SP1のころでは、.NET Frameworkは 3.5.1だったので、4がスキップされてますね。

続きを読む


DDSのRGB 10bitフォーマットの罠


今更といえば今更な話なのですが、あまり情報がないようにみえたのでここにメモしておきます。DDSフォーマットの A2R10G10B10 や A2B10G10R10 の並びの画像データについて罠というか、マイクロソフトも承知のバグが潜んでいました。具体的には、チャンネルのマスクビットが逆転しています・・・。

続きを読む