Direct3D9Ex+Direct2D

珍しくDirectXな開発ネタ。
最近またネタ切れ気味で・・・

Direct3D9ExのサーフェイスをDirect2D上で描画したいってコトがあって、
色々と調べたところ、Direct3D9Ex→Direct3D10.1→Direct2Dと
順番に共有したリソースを作ってみて描けたらラッキーかなって感触。
そして意外なことにID3D10Texture2Dと共有した
ID2D1Bitmapの情報が全然なかった・・・。
結構マイナーなコトなのかな?
そもそもDirect2D自体あまり使われてない・・・?(汗

Direct2D と Direct3D の相互運用性の概要
一応MSDNの↑のサイトに
CreateSharedBitmap を使用して IDXGISurface から ID2D1Bitmap を作成することで、Direct3D シーンをビットマップに書き込み、Direct2D を使用してレンダリングできます。とは書いてあるんだけど、それしか書いてない^^;

で、とりあえず何となくで書いてみたらあっさりイケた。

/* どこかで初期化済み
IDirect3DDevice9Ex *pD3D9Device;
ID3D10Device1 *pD3D10Device;
ID2D1RenderTarget *pD2DRenderTarget;
*/

IDirect3DSurface9 *pSurface = nullptr;
HANDLE hShared = nullptr;
ID3D10Texture2D *pTexture = nullptr;
IDXGISurface *pDxgiSurface = nullptr;
ID2D1Bitmap *pBitmap = nullptr;
D2D1_BITMAP_PROPERTIES bmpProp = {
    D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN,
    D2D1_ALPHA_MODE_IGNORE), 96.0f, 96.0f };

// サーフェイスを作成
pD3D9Device->CreateRenderTarget(1280, 720,
    D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE, 0,
    TRUE, &pSurface, &hShared);
// D3D9Exと共有されたD3D10.1のテクスチャを作成
pD3D10Device->OpenSharedResource(
    hShared, __uuidof(ID3D10Texture2D),
    reinterpret_cast<void**>(&pTexture));
// IDXGISurface を取得
pTexture->QueryInterface(IID_IDXGISurface,
    reinterpret_cast<void**>(&pDxgiSurface));
// D3D10.1と共有されたD2Dのビットマップを作成
pD2DRenderTarget->CreateSharedBitmap(
    __uuidof(IDXGISurface), pDxgiSurface,
    &bmpProp, &pBitmap);

エラー処理は省略。
処理の内容は単純に、
Direct3D9Exのサーフェイスを共有した
Direct3D10.1のテクスチャを共有した
Direct2Dのビットマップを作る感じ。(回りくどい
これでpBitmapを描画すればpSurfaceに描いた物が描けた!

D2D1_ALPHA_MODE_IGNOREを指定してアルファを無視にしてても、
サーフェイスはD3DFMT_A8R8G8B8とアルファ込みで作らないと、
D3DFMT_X8R8G8B8とかだとCreateSharedBitmapで失敗するみたい。

で、結局これで何がやりたかったかと言うと、
DirectShowのVMR9を使ってDirect2D上に動画を描画したかった!

VMR9の実装は面倒だから書かないけど、大まかなポイントだけ。
色々と試行錯誤した結果、
・InitializeDeviceでAllocateSurfaceHelperを使って
VMR9に返すサーフェイスを作りつつ、それとは別に描画用に
↑で書いたDirect2Dと共有したビットマップを作成。
・PresentImageでは描画したサーフェイスを記憶しておくだけにして、
実際に描画するときにStretchRectを使って
描画用のビットマップと共有してるサーフェイスへコピーして、
ビットマップを描画してやるとイイ感じ。

ただVSync周りとの兼ね合いでもう少し調整の余地があるかも・・・
どうもビットレートが高い動画を再生したときに
CPU負荷が上がりすぎるせいかコマ落ちが発生するけど、
VSyncを無効にするとそこそこスムーズになる現象が・・・。

余談。
今どきならVMRじゃなくてEVRでしょ!と思ったけど、
EVRの実装があまりに面倒すぎて挫折した・・・(ぇ
でも元々のCBaseVideoRendererクラスを継承して
レンダラ部分でビットマップに描画してたときよりも、
VMR9に変えたことによって2〜3割負荷が下がったからおk!

じゃ、何かして寝るー
バイニー☆

test?

コメントを残す