The ID2D1Device and ID2D1DeviceContext interfaces are new APIs introduced with Windows 8. You can use Direct2D device contexts for both Windows Store apps and desktop apps.
About Direct2D devices and device contexts
Here are some of the features and benefits of the Direct2D device and device context APIs.
Direct2D Windows Store apps
The device context is integral to creating Windows Store apps with Direct2D. Starting with Windows 8 we don't recommend rendering using methods that rely on interfaces like ID2D1HwndRenderTarget because they won't work with Windows Store apps. You can use a device context to render an Hwnd if you want to make a desktop app and still take advantage of the device context's additional features.
When you make a Direct2D Windows Store app you have several options for handling the rendering and display. You can use a device context and a DXGI swap chain to render directly to a Windows::UI::Core::CoreWindow or a Windows::UI::XAML::SwapChainBackgroundPanel. You can also use the Windows::UI::XAML::SurfaceImageSource, Windows::UI::XAML::VirtualSurfaceImageSource classes to render without a swap chain. The last three options allow you to take advantage of XAML user interface components.
Direct3D and DXGI interoperation
The ID2D1Device and ID2D1DeviceContext objects are created from and associated with a specific Direct3D device. The Direct2D device context stays associated with and logically contains all the info about the underlying Direct3D device. This way you have access to the Direct3D device if you need it and don't have to recreate it. The association of the Direct3D device and the Direct2D device context also makes it easier to apply image effects to Direct3D output.
All device contexts created from a given Direct2D device remain associated to the device, and share the settings specified on the device such as tile size.
Also, starting with Windows 8 the device context takes advantage of more of the Direct3D high color formats like:
- B8G8R8A8_UNORM_SRGB
- R8G8B8A8_UNORM_SRGB
- R16G16B16A16_UNORM
- R16G16B16A16_FLOAT
- R32G32B32A32_FLOAT
Intermediate surfaces and render targets
You can change the render target for a device context between drawing calls. The ID2D1DeviceContext::SetTarget method lets you switch the render target on the same device. You can set the render target to any bitmap or surface you create for the associated device using the Direct2D device context as long as the D2D1_BITMAP_OPTIONS_TARGET flag is set. The ID2D1DeviceContext has methods to create a Direct2D bitmap or to create a bitmap from a DXGI surface.
You can change the render target at any time before, during, and after rendering. The device context ensures that the calls to drawing methods are executed in order and applies them when you switch the render target.
In some situations, the use of an intermediate surface is made unnecessary by the device context. You can change the target the device context renders to instead of copying to an intermediate surface.
You can use a target bitmap as an intermediate surface or as a final output for rendering. An example of where it is useful to render to an intermediate surface is when you want to apply Direct2D effects to Direct2D or Direct3D primitives like this:
- Draw the primitives to an intermediate surface.
- Use the intermediate surface as input to a Direct2D effects graph.
- Use the ID2D1DeviceContext::SetTarget to switch to a new render target bitmap.
- Use the ID2D1DeviceContext::DrawImage to render the output of the effect graph to the new target.
The Direct2D device context uses the same Direct3D device for all of the primitives, effects, intermediate surfaces, and bitmaps. This means rendering, applying effects, and switching render targets is efficient and predictable.
Direct2D effects
Starting with Windows 8 Direct2D provides APIs that apply image effects. You can use Direct2D effects to apply one or more high quality effects to an image, set of images, or primitives from Direct2D or Direct3D. Direct2D effects takes advantage of GPU features and is 3D accelerated. You can chain effects in an effect graph and compose or blend the output of effects.
You use the Direct2D device context to create effects and to render the output of an effect or effect graph to a render target.
Creating a Direct2D device context for rendering
To get a Direct2D device context, you must first create a Direct3D device to handle the management and rendering of graphical resources.
Create a Direct2D factory
First, create a ID2D1Factory1 object. The Direct2D factory is device independent and you use it to create a ID2D1Device later.
D2D1_FACTORY_OPTIONS options;
ZeroMemory(&options, sizeof(D2D1_FACTORY_OPTIONS));
DX::ThrowIfFailed(
D2D1CreateFactory(
D2D1_FACTORY_TYPE_SINGLE_THREADED,
__uuidof(ID2D1Factory1),
&options,
&m_d2dFactory
)
);
Create a Direct3D 11 device and query it for its DXGI device interface
Create an Direct3D device object, and query it for the DXGI device that will allow it to interact with the Direct2D device context that you will create later.
-
Declare the creation flags to set up the Direct3D device for BGRA support. Direct2D requires BGRA color order.
// This flag adds support for surfaces with a different color channel ordering than the API default. // You need it for compatibility with Direct2D. UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; -
Declare an array of D3D_FEATURE_LEVELentries representing the set of feature levels that your app will support. Direct3D works its way down the list that you provide until it finds a feature level supported by the host system.
// This array defines the set of DirectX hardware feature levels this app supports. // The ordering is important and you should preserve it. // Don't forget to declare your app's minimum required feature level in its // description. All apps are assumed to support 9.1 unless otherwise stated. D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_3, D3D_FEATURE_LEVEL_9_2, D3D_FEATURE_LEVEL_9_1 };Note This array is optional. You can pass null to the featureLevels parameter of the D3D11CreateDevice function in the next step and Direct3D will select the highest available feature level. Use a feature level array if you are using Direct3D only offered at or above a specific feature level.
-
Use the D3D11CreateDevice function to create both a ID3D11Device object and a ID3D11DeviceContext object.
// Create the DX11 API device object, and get a corresponding context. ComPtr<ID3D11Device> device; ComPtr<ID3D11DeviceContext> context; DX::ThrowIfFailed( D3D11CreateDevice( nullptr, // specify null to use the default adapter D3D_DRIVER_TYPE_HARDWARE, 0, creationFlags, // optionally set debug and Direct2D compatibility flags featureLevels, // list of feature levels this app can support ARRAYSIZE(featureLevels), // number of possible feature levels D3D11_SDK_VERSION, &device, // returns the Direct3D device created &m_featureLevel, // returns feature level of device created &context // returns the device immediate context ) );When this function returns, you have a ID3D11Device that you can use in Windows Store apps.
-
Query the Direct3D 11 device for its DXGI Device interface.
The ID3D11Device interface also implements the IDXGIDevice interface so you can then get the underlying DXGI Device from it.
ComPtr<IDXGIDevice> dxgiDevice; // Obtain the underlying DXGI device of the Direct3D11 device. DX::ThrowIfFailed( device.As(&dxgiDevice) );
Create the Direct2D device and device context
Create a ID2D1Device object using the ID2D1Factory::CreateDevice method and passing in the IDXGIDevice object. Then, create a ID2D1DeviceContext object using the ID2D1Device::CreateDeviceContext method.
// Obtain the Direct2D device for 2-D rendering.
DX::ThrowIfFailed(
m_d2dFactory->CreateDevice(dxgiDevice.Get(), &m_d2dDevice)
);
// Get Direct2D device's corresponding device context object.
DX::ThrowIfFailed(
m_d2dDevice->CreateDeviceContext(
D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
&m_d2dContext
)
);
The newly created Direct2D device context is associated with the Direct3D device via the DXGI device.
Create a DXGI swap chain
The newly created Direct2D device context needs a target surface to render onto. The IDXGISwapChain interface provides a back buffer for the Direct2D device context to render to and handles drawing to the window by swapping the back buffer with the visible buffer.
-
Allocate a DXGI_SWAP_CHAIN_DESC1 structure and define the settings for the swap chain.
These settings show an example of how to create a swap chain that a Windows Store app can use.
// Allocate a descriptor. DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0}; swapChainDesc.Width = 0; // use automatic sizing swapChainDesc.Height = 0; swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // this is the most common swapchain format swapChainDesc.Stereo = false; swapChainDesc.SampleDesc.Count = 1; // don't use multi-sampling swapChainDesc.SampleDesc.Quality = 0; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.BufferCount = 2; // use double buffering to enable flip swapChainDesc.Scaling = DXGI_SCALING_NONE; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // all apps must use this SwapEffect swapChainDesc.Flags = 0; -
Get the adapter that the Direct3D device and the DXGI device are running on and get the IDXGIFactory object associated with them. You must use this DXGI factory to ensure the swap chain is created on the same adapter.
// Identify the physical adapter (GPU or card) this device is runs on. ComPtr<IDXGIAdapter> dxgiAdapter; DX::ThrowIfFailed( dxgiDevice->GetAdapter(&dxgiAdapter) ); // Get the factory object that created the DXGI device. ComPtr<IDXGIFactory2> dxgiFactory; DX::ThrowIfFailed( dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory)) ); -
Use the IDXGIFactory2::CreateSwapChainForCoreWindow method to create the swap chain. Use the Windows::UI::CoreWindow class for the main window of a Windows Store app.
Make sure to set the maximum frame latency to 1 to minimize power consumption.
// Get the final swap chain for this window from the DXGI factory. DX::ThrowIfFailed( dxgiFactory->CreateSwapChainForCoreWindow( device.Get(), reinterpret_cast<IUnknown*>(m_window), &swapChainDesc, nullptr, // allow on all displays &m_swapChain ) ); // Ensure that DXGI doesn't queue more than one frame at a time. DX::ThrowIfFailed( dxgiDevice->SetMaximumFrameLatency(1) );If you want to render Direct2D content in a XAML app, see the CreateSwapChainForComposition method.
Get the 2D texture back buffer from Direct3D
You must get the 2 dimensional Direct3D texture for the window back buffer. You create a bitmap target that links to this texture for the Direct2D device context to render to in the next step.
-
Get the back buffer from the swap chain. The back buffer is an ID3D11Texture2D object that the swap chain allocates when the swap chain is created.
// Get the backbuffer for this window which is be the final 3D render target. ComPtr<ID3D11Texture2D> backBuffer; DX::ThrowIfFailed( m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer)) );
Create a Direct2D bitmap from the back buffer
Finally, you can create an ID2D1Bitmap object that is linked to the back buffer surface of the swap chain. When you render to the Direct2D bitmap it renders directly to the back buffer.
-
Declare a D2D1_BITMAP_PROPERTIES1 struct and set the property values. It is important to set the pixel format to BGRA because this is the format the Direct3D device and the DXGI device are set to use this format.
// Now we set up the Direct2D render target bitmap linked to the swapchain. // Whenever we render to this bitmap, it is directly rendered to the // swap chain associated with the window. D2D1_BITMAP_PROPERTIES1 bitmapProperties = BitmapProperties1( D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW, PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE), m_dpi, m_dpi ); -
Get the back buffer as a IDXGISurface to pass to Direct2D. Direct2D doesn't accept a ID3D11Texture2D directly.
Create a ID2D1Bitmap object from the back buffer using the ID2D1DeviceContext::CreateBitmapFromDxgiSurface method.
// Direct2D needs the dxgi version of the backbuffer surface pointer. ComPtr<IDXGISurface> dxgiBackBuffer; DX::ThrowIfFailed( m_swapChain->GetBuffer(0, IID_PPV_ARGS(&dxgiBackBuffer)) ); // Get a D2D surface from the DXGI back buffer to use as the D2D render target. DX::ThrowIfFailed( m_d2dContext->CreateBitmapFromDxgiSurface( dxgiBackBuffer.Get(), &bitmapProperties, &m_d2dTargetBitmap ) ); -
Now the Direct2D bitmap is linked to the back buffer. Set the target on the Direct2D device context to the bitmap.
// Now we can set the Direct2D render target. m_d2dContext->SetTarget(m_d2dTargetBitmap.Get());Note We recommend that you set the target after you call the BeginDraw method, perform the rendering operations, call SetTarget with the parameter set to NULL, and then call the EndDraw method to ensure that Direct2D does not hold a reference to the back buffer.
Rendering and displaying
Now that you have a target bitmap, you can draw primitives, images, image effects, and text to it using the Direct2D device context. After you render to the bitmap target, you display the result by calling the IDXGISwapChain::Present method.
Note You must call the EndDraw method before you call Present so the Direct2D rendering operations are finished when the result is presented.
When the swap chain presents, it swaps the back buffer with the on screen buffer. The Direct2D bitmap that is linked to the back buffer still points to the off screen buffer.
Send comments about this topic to Microsoft
Build date: 11/29/2012