HDD の中の実験コードらを整理していたらずいぶん前に作っていた NV_DX_interop 拡張を利用したコードを発見しました。
OpenGL と DirectX9 を1つのアプリケーションの中で使い、リソースを共有して使えるという点が魅力的です。
WGL_NV_DX_interop
この WGL_NV_DX_interop 拡張は名前の通り NVIDIA のベンダー拡張として定義されています。
詳しい説明は OpenGL Registry の https://www.opengl.org/registry/specs/NV/DX_interop.txt を参照してください。
この拡張では OpenGL と DirectX9 のリソースを共有を実現します。以下のリソースが共有できるようです。
- テクスチャ(2D, 3D,Cubemap)
- 頂点・インデックスバッファ
API をまたいで、リソースを使えるという点で非常に興味深いですね。
リソースの準備
OpenGL と DirectX9 の各リソースを共有してそれぞれで使ってみる実験をしてみました。
DirectX9 側で今までと違う点は、共有ハンドルを取得するように各リソースを作成することです。
CreateTexture の最後の引数で HANDLE* を指定する部分があります。
ここを NULL にしておくことがほとんどでしたが、今回はここを使用します。
DirectX9 では D3DX が使えたので、 PNG ファイルからテクスチャを作成しました。
しかし、 D3DX の関数がハンドルを受け取れるようになっていなくてそのままは使えませんでした。
いったんシステムメモリにテクスチャを作成するようにして、 UpdateTexture で転送するという方式を採用しました。
テクスチャの準備が整ったらこれを OpenGL でも使えるように wglDXSetResourceShareHandleNV, wglDXRegisterObjectNV を呼び出して共有ハンドルを得ます。
これらのコード例は以下のようになります。
D3DXCreateTextureFromFileEx( ..., D3DPOOL_SYSTEMMEM, ..., &pStaging ); pd3ddevice->CreateTexture( ..., D3DPOOL_DEFAULT, &pTextureDX9, &hHandle ); pd3ddevice->UpdateTexture( pStaging, pTextureDX9 ); wglDXSetResourceShareHandleNV( pTextureDX9, hHandle ); hInteropShare = wglDXRegisterObjectNV( ..., pTextureDX9, texID, GL_TEXTURE_2D, WGL_ACCESS_READ_WRITE_NV );
次に OpenGL でレンダーターゲットを作成し、これを DirectX9 側で使うための準備をしました。
ほぼほぼテクスチャの作成と同じ手順ですが FBO(Framebuffer Object) を作成する前に、カラーテクスチャについて wglDXSetResourceShareHandleNV を呼び出して共有ハンドルを得ておきます。
描画について
DirectX9 で描画するフェーズ、 OpenGL で描画するフェーズの境目で、リソースにロックをかけて同期をとるような仕組みです。
wglDXLockObjectsNV( ..., hSharedHandles ); // OpenGL による描画処理 renderGL(); wglDXUnlockObjectsNV( ..., hSharedHandles ); // DirectX9 による描画処理 renderDX9();
こうやって混在した描画結果は以下のようになります。
最終描画は DirectX9 でやっていますが、チェッカーテクスチャは OpenGL のものです。
また DirectX9 テクスチャを OpenGL と共有し、画面中央のレンダーテクスチャは OpenGL で描画したものという混在させてみた結果です。
今回の動作環境は Windows10 (x64), GeForce 650 Ti のもので試しています。
まとめ
この拡張機能は仕様を見ると 2010 年付近に登場しているようです。
今回のコードらは 2015 年の正月あたりに作成していたようです。
当時の記録によると Intel, AMD らのドライバでもサポートしているようでした。
しかし、挙動が3社で変わるようなので、本拡張を使うならテスト環境も十分に用意しないといけないのは間違いないでしょう。
NVIDIA のドライバが 2016.07 リリースの 368.81 は WindowsXP に対して提供されていました。
未検証ですが、 Windows XP でも今回の拡張が使えるとなると XP でも DirectX9 をメインに使いつつ、部分的に OpenGL に任せてジオメトリシェーダーによる描画結果を得ることができそうです。