Direct2D導入(ID2D1DeviceContext)
下記記事にて、ID2D1HwndRenderTargetを利用してDirect2Dを利用してみました。
Direct2D導入(ID2D1HwndRenderTarget) - 何でもプログラミング
Direct2D 1.1からは、ID2D1DeviceContextを利用して実装するようになっています。
今回はID2D1DeviceContextを用いて上記記事と同じアプリを作成してみたいと思います。

記事中のCreateHWND関数、Run関数は上記記事を参照してください。
IDXGIDevice1の作成
まずはIDXGIDevice1を作成します。
ID3D11Deviceを作成して、そこからIDXGIDevice1を取得します。
#include <dxgi1_2.h> #include <d3d11.h> #pragma comment(lib, "d3d11.lib") ComPtr<IDXGIDevice1> CreateDXGIDevice() { ComPtr<ID3D11Device> device; AssertHR(D3D11CreateDevice( nullptr, D3D_DRIVER_TYPE_HARDWARE, 0, D3D11_CREATE_DEVICE_BGRA_SUPPORT, // Direct2Dではこのフラグが必要 nullptr, 0, D3D11_SDK_VERSION, &device, nullptr, nullptr )); ComPtr<IDXGIDevice1> dxgiDevice; AssertHR(device.As(&dxgiDevice)); AssertHR(dxgiDevice->SetMaximumFrameLatency(1)); // レイテンシを最小にしておく return dxgiDevice; }
ID2D1DeviceContextの作成
IDXGIDevice1を利用して、ID2D1DeviceContextを作成します。
#include <d2d1_1.h> #pragma comment(lib, "d2d1.lib") ComPtr<ID2D1DeviceContext> CreateD2DContext(IDXGIDevice1* dxgiDevice) { ComPtr<ID2D1Factory1> factory; AssertHR(D2D1CreateFactory<ID2D1Factory1>(D2D1_FACTORY_TYPE_SINGLE_THREADED, &factory)); ComPtr<ID2D1Device> device; AssertHR(factory->CreateDevice(dxgiDevice, &device)); ComPtr<ID2D1DeviceContext> context; AssertHR(device->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, &context)); return context; }
IDXGISwapChain1の作成
Windowに描画結果を表示するため、SwapChainを作成します。
またSwapChainのBackBufferのID2D1Bitmap1を作成する関数も準備します。
ComPtr<IDXGISwapChain1> CreateSwapChain(IDXGIDevice1* device, HWND hwnd)
{
ComPtr<IDXGIAdapter> adapter;
AssertHR(device->GetAdapter(&adapter));
ComPtr<IDXGIFactory2> factory;
AssertHR(adapter->GetParent(IID_PPV_ARGS(&factory)));
DXGI_SWAP_CHAIN_DESC1 desc = { 0 };
desc.Width = 0; // 自動でWindowのサイズが設定される
desc.Height = 0;
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
desc.Stereo = false;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
desc.BufferCount = 2;
desc.Scaling = DXGI_SCALING_NONE;
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
desc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
desc.Flags = 0;
ComPtr<IDXGISwapChain1> swapChain;
AssertHR(factory->CreateSwapChainForHwnd(
device,
hwnd,
&desc,
nullptr,
nullptr,
&swapChain
));
return swapChain;
}
ComPtr<ID2D1Bitmap1> CreateBackBufferBitmap(ID2D1DeviceContext* context, IDXGISwapChain1* swapChain)
{
ComPtr<IDXGISurface> backBuffer;
AssertHR(swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer)));
auto prop = D2D1::BitmapProperties1(
D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE)
);
ComPtr<ID2D1Bitmap1> bitmap;
AssertHR(context->CreateBitmapFromDxgiSurface(backBuffer.Get(), &prop, &bitmap));
return bitmap;
}
楕円描画関数
Windowいっぱいに楕円を描画します。
void Draw(ID2D1DeviceContext* context) { context->BeginDraw(); context->Clear(D2D1::ColorF(D2D1::ColorF::LightYellow)); D2D1_SIZE_F size = context->GetSize(); float rx = size.width / 2; float ry = size.height / 2; D2D1_ELLIPSE ellipse = D2D1::Ellipse(D2D1::Point2F(rx, ry), rx, ry); ComPtr<ID2D1SolidColorBrush> brush; AssertHR(context->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Orange), &brush)); context->FillEllipse(ellipse, brush.Get()); AssertHR(context->EndDraw()); }
アプリケーションコード
Drawで描画した際、Windowに表示するためにSwapChainのPresentを呼び出す必要があります。
サイズ変更は、一度ContextのTargetから外し、ResizeBuffersで変更した後、再度Targetに設定する必要があります。
ComPtr<ID2D1DeviceContext> g_context;
ComPtr<IDXGISwapChain1> g_swapChain;
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_PAINT:
{
Draw(g_context.Get());
DXGI_PRESENT_PARAMETERS params = { 0 };
AssertHR(g_swapChain->Present1(1, 0, ¶ms));
}
return 0;
case WM_SIZE:
g_context->SetTarget(nullptr);
AssertHR(g_swapChain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0)); // サイズ0で、自動でWindowのサイズが設定される
g_context->SetTarget(CreateBackBufferBitmap(g_context.Get(), g_swapChain.Get()).Get());
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
int main() { HWND hwnd = CreateHWND(WndProc); auto dxgiDevice = CreateDXGIDevice(); g_context = CreateD2DContext(dxgiDevice.Get()); g_swapChain = CreateSwapChain(dxgiDevice.Get(), hwnd); g_context->SetTarget(CreateBackBufferBitmap(g_context.Get(), g_swapChain.Get()).Get()); Run(hwnd); return 0; }