WPFとDirect3D11の連携 --- 導入
下記記事にてWPFとDirect3D9Exを連携する方法を記述しました。
WPFとDirect3D9Exの連携 --- 導入 - 何でもプログラミング
最近ではDirect3D11の利用がメジャーになっていますので、今回はWPFとDirect3D11を連携させてみたいと思います。
WPF自体はDirect3D9ですので、リソースを共有する仕組みでDirect3D11と連携します。
本記事で利用しているCliComPtr、AssertHR、D3D9Ex::CreateDeviceは上記記事を参照してください。
Device作成
DeviceとDeviceContextを作成しています。
createDeviceFlagやpFeatureLevelsは適宜カスタマイズしてください。(下記ではFeatureLevelは11、10.1、10、9.3、9.2、9.1から選択されます。)
#include <d3d11.h> #pragma comment(lib, "d3d11.lib") std::tuple<CComPtr<ID3D11Device>, CComPtr<ID3D11DeviceContext>> CreateDevice() { #ifdef _DEBUG DWORD createDeviceFlag = D3D11_CREATE_DEVICE_DEBUG; #else DWORD createDeviceFlag = 0; #endif CComPtr<ID3D11Device> device; CComPtr<ID3D11DeviceContext> context; D3D_FEATURE_LEVEL createdFeatureLevel; AssertHR(D3D11CreateDevice( NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, createDeviceFlag, NULL, 0, D3D11_SDK_VERSION, &device.p, &createdFeatureLevel, &context.p)); return { device, context }; }
共有RenderTarget作成(Direct3D9Ex)
Direct3D11で利用できるDirect3D9ExのRenderTargetを作成します。
CreateRenderTargetの最後の引数からHANDLEを取得しているとこが通常との違いです。
std::tuple<CComPtr<IDirect3DSurface9>, HANDLE> CreateSharedRenderTarget(IDirect3DDevice9Ex* device, int width, int height) { CComPtr<IDirect3DSurface9> surface; HANDLE handle = nullptr; AssertHR(device->CreateRenderTarget( width, height, D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE, 0, FALSE, &surface.p, &handle)); return { surface, handle }; }
共有RenderTargetを開く
Direct3D9Exで作成したRenderTargetをDirect3D11側で開きます。
CComPtr<ID3D11RenderTargetView> OpenRenderTarget(ID3D11Device* device, HANDLE handle) { CComPtr<ID3D11Resource> resource; AssertHR(device->OpenSharedResource(handle, __uuidof(ID3D11Resource), (void**)&resource.p)); CComPtr<ID3D11RenderTargetView> renderTarget; AssertHR(device->CreateRenderTargetView(resource, NULL, &renderTarget.p)); return renderTarget; }
Renderer作成
赤い背景を描画するだけの内容となっています。
ref classとstd::tieを上手く連携させられなかったため、Tie2マクロを定義しています。
共有リソースを利用している場合は描画の最後にID3D11DeviceContext::Flushを呼び出す必要があります。
#define Tie2(x1, x2, expr) { auto t = expr; x1 = std::get<0>(t); x2 = std::get<1>(t); } public ref class Renderer { public: property IntPtr Surface { IntPtr get() { return IntPtr(_surface9); } } Renderer(int width, int height) { _device9 = D3D9Ex::CreateDevice(); HANDLE handle; Tie2(_surface9, handle, D3D9Ex::CreateSharedRenderTarget(_device9, width, height)); Tie2(_device, _context, CreateDevice()); _renderTarget = OpenRenderTarget(_device, handle); ID3D11RenderTargetView* renderTargets[1] = { _renderTarget }; _context->OMSetRenderTargets(1, renderTargets, NULL); float clearColor[4] = { 1.0f, 0.0f, 0.0f, 1.0f }; _context->ClearRenderTargetView(_renderTarget, clearColor); _context->Flush(); }; private: CliComPtr<IDirect3DDevice9Ex> _device9; CliComPtr<IDirect3DSurface9> _surface9; CliComPtr<ID3D11Device> _device; CliComPtr<ID3D11DeviceContext> _context; CliComPtr<ID3D11RenderTargetView> _renderTarget; };