Here's the code:
#include <windows.h>#include <D3D11.h>#include <D2D1.h>#include <DXErr.h>#include <DXGI.h>// Libs#pragma comment (lib, "D3D11.lib")#pragma comment (lib, "D2D1.lib")#pragma comment (lib, "DXErr.lib")#pragma comment (lib, "DXGI.lib")LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);// Mainint WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // Register windowclass WNDCLASSEX wc; ZeroMemory(&wc, sizeof(wc)); wc.cbSize = sizeof(wc); wc.lpszClassName = TEXT("MyClass"); wc.hInstance = hInstance; wc.lpfnWndProc = WndProc; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); RegisterClassEx(&wc); // Create window HWND hWnd = CreateWindow( wc.lpszClassName, TEXT("D3D11 with Direct2D"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL ); // Create DXGI factory to enumerate adapters IDXGIFactory1 *pDXGIFactory; HRESULT hResult = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&pDXGIFactory); if(FAILED(hResult)) { MessageBox(NULL, DXGetErrorDescription(hResult), TEXT("CreateDXGIFactory1"), MB_OK); return 0; } // Use the first adapter IDXGIAdapter1 *pAdapter; hResult = pDXGIFactory->EnumAdapters1(0, &pAdapter); if(FAILED(hResult)) { MessageBox(NULL, DXGetErrorDescription(hResult), TEXT("EnumAdapters1"), MB_OK); return 0; } pDXGIFactory->Release(); // Create D3D11 device and swapchain DXGI_SWAP_CHAIN_DESC scd; ID3D11Device *pDevice11; IDXGISwapChain *pSwapChain; ID3D11DeviceContext *pImmediateContext; ZeroMemory(&scd, sizeof(scd)); scd.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; scd.SampleDesc.Count = 1; scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; scd.BufferCount = 1; scd.OutputWindow = hWnd; scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; scd.Windowed = TRUE; hResult = D3D11CreateDeviceAndSwapChain( pAdapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, D3D11_CREATE_DEVICE_DEBUG | D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_SINGLETHREADED, NULL, 0, D3D11_SDK_VERSION, &scd, &pSwapChain, &pDevice11, NULL, &pImmediateContext ); if(FAILED(hResult)) { MessageBox(NULL, DXGetErrorDescription(hResult), TEXT("D3D11CreateDeviceAndSwapChain"), MB_OK); return 0; } // Get the D3D11 back-buffer ID3D11Texture2D *pBackBuffer11; D3D11_TEXTURE2D_DESC backBufferDesc; hResult = pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&pBackBuffer11)); if(FAILED(hResult)) { MessageBox(NULL, DXGetErrorDescription(hResult), TEXT("pSwapChain->GetBuffer for ID3D11Texture2D"), MB_OK); return 0; } pBackBuffer11->GetDesc(&backBufferDesc); // Create the texture to draw D2D content to D3D11_TEXTURE2D_DESC textureDesc; ID3D11Texture2D *pTexture; ZeroMemory(&textureDesc, sizeof(textureDesc)); textureDesc.Width = backBufferDesc.Width; textureDesc.Height = backBufferDesc.Height; textureDesc.MipLevels = 1; textureDesc.ArraySize = 1; textureDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; textureDesc.SampleDesc.Count = 1; textureDesc.Usage = D3D11_USAGE_DEFAULT; textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; textureDesc.MiscFlags = D3D11_RESOURCE_MISC_GDI_COMPATIBLE; hResult = pDevice11->CreateTexture2D(&textureDesc, NULL, &pTexture); if(FAILED(hResult)) { MessageBox(NULL, DXGetErrorDescription(hResult), TEXT("pDevice11->CreateTexture2D"), MB_OK); return 0; } // Get DXGI surface from texture IDXGISurface1 *pSurface; hResult = pTexture->QueryInterface(__uuidof(IDXGISurface1), (void**)&pSurface); if(FAILED(hResult)) { MessageBox(NULL, DXGetErrorDescription(hResult), TEXT("pTexture->QueryInterface for IDXGISurface1"), MB_OK); return 0; } // Create D2D factory ID2D1Factory *pD2DFactory; hResult = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory), (void**)&pD2DFactory); if(FAILED(hResult)) { MessageBox(NULL, DXGetErrorDescription(hResult), TEXT("D2D1CreateFactory"), MB_OK); return 0; } // Create D2D DC render target D2D1_RENDER_TARGET_PROPERTIES renderTargetProperties; ID2D1DCRenderTarget *pD2DRenderTarget; ZeroMemory(&renderTargetProperties, sizeof(renderTargetProperties)); renderTargetProperties.type = D2D1_RENDER_TARGET_TYPE_HARDWARE; renderTargetProperties.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED); hResult = pD2DFactory->CreateDCRenderTarget(&renderTargetProperties, &pD2DRenderTarget); if(FAILED(hResult)) { MessageBox(NULL, DXGetErrorDescription(hResult), TEXT("pD2DFactory->CreateDCRenderTarget"), MB_OK); return 0; } pD2DFactory->Release(); // Create a solid color brush to draw something with ID2D1SolidColorBrush *pBrush; hResult = pD2DRenderTarget->CreateSolidColorBrush(D2D1::ColorF(1.0f, 1.0f, 0.0f, 1.0f), &pBrush); if(FAILED(hResult)) { MessageBox(NULL, DXGetErrorDescription(hResult), TEXT("pD2DRenderTarget->CreateSolidColorBrush"), MB_OK); return 0; } // Main loop float angle = 0.0f; ShowWindow(hWnd, nCmdShow); while(true) { MSG msg; if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != 0) { if(msg.message == WM_QUIT) break; else { TranslateMessage(&msg); DispatchMessage(&msg); } } else { // Get surface DC for the texture HDC hDC; hResult = pSurface->GetDC(TRUE, &hDC); if(FAILED(hResult)) { } else { // The rect of the texture to draw to with D2D RECT rect; SetRect(&rect, 0, 0, backBufferDesc.Width, backBufferDesc.Height); // Bind the DC render target to the HDC hResult = pD2DRenderTarget->BindDC(hDC, &rect); if(FAILED(hResult)) { } else { // Draw D2D content angle += 360.0f / 200.0f; pD2DRenderTarget->BeginDraw(); pD2DRenderTarget->Clear(D2D1::ColorF(0.0f, 0.7f, 0.0f, 1.0f)); D2D1_SIZE_F size = pD2DRenderTarget->GetSize(); pD2DRenderTarget->SetTransform(D2D1::Matrix3x2F::Rotation(angle, D2D1::Point2F(size.width/2.0f, size.height/2.0f))); pBrush->SetColor(D2D1::ColorF(1.0f, 1.0f, 0.0f, 1.0f)); pD2DRenderTarget->DrawEllipse( D2D1::Ellipse(D2D1::Point2F(size.width/2.0f, size.height/2.0f), size.height/3.0f, size.height/3.0f), pBrush, 32.0f, NULL ); pBrush->SetColor(D2D1::ColorF(1.0f, 0.0f, 0.0f, 1.0f)); pD2DRenderTarget->DrawEllipse( D2D1::Ellipse(D2D1::Point2F(size.width/4.0f, size.height/2.0f), size.height/4.0f, size.height/4.0f), pBrush, 32.0f, NULL ); pBrush->SetColor(D2D1::ColorF(0.0f, 0.0f, 1.0f, 1.0f)); pD2DRenderTarget->DrawEllipse( D2D1::Ellipse(D2D1::Point2F(size.width*3.0f/4.0f, size.height/2.0f), size.height/4.0f, size.height/4.0f), pBrush, 32.0f, NULL ); pD2DRenderTarget->EndDraw(); } // Release the DC specifying the dirty rect pSurface->ReleaseDC(&rect); } // Copy the content from the texture to the back-buffer pImmediateContext->CopyResource(pBackBuffer11, pTexture); // Present to screen pSwapChain->Present(1, 0); } } // Release pSwapChain->SetFullscreenState(FALSE, NULL); pImmediateContext->ClearState(); pBrush->Release(); pD2DRenderTarget->Release(); pSurface->Release(); pTexture->Release(); pBackBuffer11->Release(); pImmediateContext->Flush(); pImmediateContext->Release(); pSwapChain->Release(); pDevice11->Release(); UnregisterClass(wc.lpszClassName, hInstance); return 0;}// Window procedureLRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { // Window destroyed. case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hWnd, msg, wParam, lParam);}
EDIT: I noticed that at least for simple test-cases it's faster to use software-mode for the D2D render-target with this method. I assume it's because it copies back-and-forth between GPU and system memory otherwise..
It's significantly slower than using the shared texture method, when drawing large areas.
[Edited by - Erik Rufelt on November 9, 2009 12:58:40 PM]