ID2D1CommandList interface (d2d1_1.h)

Represents a sequence of commands that can be recorded and played back.

Inheritance

The ID2D1CommandList interface inherits from ID2D1Image. ID2D1CommandList also has these types of members:

Methods

The ID2D1CommandList interface has these methods.

 
ID2D1CommandList::Close

Instructs the command list to stop accepting commands so that you can use it as an input to an effect or in a call to ID2D1DeviceContext::DrawImage.
ID2D1CommandList::Stream

Streams the contents of the command list to the specified command sink.

Remarks

The command list does not include static copies of resources with the recorded set of commands. All bitmaps, effects, and geometries are stored as references to the actual resource and all the brushes are stored by value. All the resource creation and destruction happens outside of the command list. The following table lists resources and how they are treated inside of a command list.

Resource How it is treated by the command list
Solid-color brush Passed by value.
Bitmap brush The brush is passed by value but the bitmap that is used to create the brush is in fact referenced.
Gradient brushes – both linear and radial gradient The brush is passed by value but the gradient stop collection itself is referenced. The gradient stop collection object is immutable.
Bitmaps Passed by reference.
Drawing state block The actual state on the device context is converted into set functions like set transform and is passed by value.
Geometry Immutable object passed by value.
Stroke style Immutable object passed by value.
Mesh Immutable object passed by value.
 

Using a CommandList as a Target

The following pseudocode illustrates the different cases where a target is set as either a command list or as a bitmap.
//create a D2D device from an already created DXGI device 
ID2D1Device *pD2D1Device;
pD2D1Factory->CreateDevice(pDxgiDevice, &pD2D1Device);

//create a D2D device context from the D2D device
ID2D1DeviceContext *pD2D1DeviceContext;
pD2D1Device->CreateD2D1DeviceContext(&pD2D1DeviceContext);

//create command list
ID2D1CommandList *pCommandList1;
pD2D1DeviceContext->CreateCommandList(&pCommandList1);

//CreateBitmap
ID2D1Bitmap *pBitmap1;
ID2D1Bitmap *pBitmap2;
pD2D1DeviceContext->CreateBitmap(…, &pBitmap1);
pD2D1DeviceContext->CreateBitmap(…, &pBitmap2);

//Set the bitmap as the target
pD2D1DeviceContext->SetTarget(pBitmap1);
pD2D1DeviceContext->BeginDraw();
RenderMyVectorContent(pD2D1DeviceContext);
pD2D1DeviceContext->EndDraw();

//Set the command list as the target
pD2D1DeviceContext->SetTarget(pCommandList1);
pD2D1DeviceContext->BeginDraw();
RenderMyVectorContent(pD2D1DeviceContext);
pD2D1DeviceContext->EndDraw();

//Drawing a command list to a bitmap target
pD2D1DeviceContext->SetTarget(pBitmap2);
pD2D1DeviceContext->BeginDraw();
pD2D1DeviceContext->DrawImage(pCommandList1);
pD2D1DeviceContext->EndDraw();
  • Set the bitmap as the target:In this case, all contents rendered to the bitmap are rasterized. If this bitmap is used somewhere else, it will not be resolution independent and if a transformation like High Quality Scale is used, it will not maintain fidelity.
  • Set the command list as the target:In this case, instead of the scene being rasterized, all of the commands are recorded. When the command list is used later for screen drawing using ID2D1DeviceContext::DrawImage or passed to an XPS print control, the vector content is replayed with no loss of fidelity.
  • Drawing a command list to a bitmap target:In this case because the target is a bitmap, the command list is drawn to the bitmap and is no longer resolution independent.
The only way to retain vector content for later playback with full fidelity is to set the target type as a command list. When a bitmap is set as a target, any drawing on that target will get rasterized.

Using a CommandList to Create a Brush

Command lists are a good way to support pattern brushes, because they are capable of retaining fidelity on replay. The desired pattern can be stored as a command list, which can be used to create an image brush. This brush can then be used to paint paths.

The type of brush that supports filling a path with a command list is called an image brush.

The following psuedocode illustrates the process of using a command list with an image brush.

//Draw the pattern to the command list
ID2D1CommandList *pCommandList;
pD2D1DeviceContext->SetTarget(pCommandList);
pD2D1DeviceContext->BeginDraw();
DrawMyPattern(pD2D1DeviceContext);
pD2D1DeviceContext->EndDraw();

//Create the image brush from the command list
ID2D1ImageBrush *pImageBrush;
pD2D1DeviceContext->CreateImageBrush(
	pCommandList, 
	pImageBrushProperties,
	pBrushProperties,
	&pImageBrush);

//Fill the ellipse with the pattern brush
pD2D1DeviceContext->SetTarget(pTargetBitmap);
pD2D1DeviceContext->BeginDraw();
pD2D1DeviceContext->FillEllipse(pEllipse, pImageBrush);
pD2D1DeviceContext->EndDraw();

Because the brush accepts an image, it has the following other benefits as well:

  • Because the output of an effect graph is an image, this image can be used to create an image brush, which effectively provides the capability of using an effect as a fill.
  • Because the command list is a type of image, vector content can be inserted into an effect graph and can also be tiled or operated on. For example, a large copyright notice can be inserted over a graph with a virtualized image and then encoded.

Using a CommandList as a Replacement for a Compatible Render Target

Compatible render targets are used very often for off-screen rendering to an intermediate bitmap that is later composited with the actual scene. Especially in the case of printing, using compatible render targets will increase the memory footprint because everything will be rasterized and sent to XPS instead of retaining the actual primitives. In this scenario, a developer is better off replacing the compatible render target with an intermediate command list. The following pseudo code illustrates this point.
pD2D1Device->CreateDeviceContext(&pD2D1DeviceContext);
pRenderTarget->CreateCompatibleRenderTarget(…, &pCompatibleRenderTarget);

//render to the compatible render target
pCompatibleRenderTarget->BeginDraw();
RenderMyScene1(pCompatibleRenderTarget);
pCompatibleRenderTarget->EndDraw();

//get the bitmap from the compatible render target
pCompatibleRenderTarget->GetBitmap(pCompatBitmap);

//draw this bitmap on the device context
pD2D1DeviceContext->SetTarget(pTargetBitmap)
pD2D1DeviceContext->BeginDraw();
pD2D1DeviceContext->DrawBitmap(pCompatBitmap);
pD2D1DeviceContext->EndDraw();

//draw something else on the compatible render target
pCompatibleRenderTarget->BeginDraw();
pCompatibleRenderTarget->Clear();
pCompatibleRenderTarget>RenderScene2();
pCompatibleRenderTarget->EndDraw();

//get the bitmap from the compatible render target
pCompatibleRenderTarget->GetBitmap(pCompatBitmap);

//draw this bitmap on the device context
pD2D1DeviceContext->SetTarget(pTargetBitmap)
pD2D1DeviceContext->BeginDraw();
pD2D1DeviceContext->DrawBitmap(pCompatBitmap);
pD2D1DeviceContext->EndDraw();


//Use a command list instead for better quality and performance 

//store the original target
pOriginalTarget = pD2D1DeviceContext->GetTarget();

pD2D1DeviceContext->CreateCommandList(pCommandList1);

//draw to command list 1
pD2D1DeviceContext->SetTarget(pCommandList1);
pD2D1DeviceContext->BeginDraw();
RenderMyScene1(pD2D1DeviceContext);
pD2D1DeviceContext->EndDraw();

//draw the command list to the original target
pD2D1DeviceContext->SetTarget(pOriginalTarget);
pD2D1DeviceContext->BeginDraw();
pD2D1DeviceContext->DrawImage(pCommandList1);
pD2D1DeviceContext->EndDraw();

pD2D1DeviceContext->CreateCommandList(pCommandList2);

//draw something else to a new command list
pD2D1DeviceContext->SetTarget(pCommandList2);
pD2D1DeviceContext->BeginDraw();
pD2D1DeviceContext->RenderScene2();
pD2D1DeviceContext->EndDraw();

//draw the new command list on the old command list
pD2D1DeviceContext->SetTarget(pCommandList1);
pD2D1DeviceContext->BeginDraw();
pD2D1DeviceContext->DrawImage(pCommandList2);
pD2D1DeviceContext->EndDraw();

Working with Other APIs

Direct2D employs a simple model when interoperating with GDI and Direct3D/DXGI APIs. The command list does not record these commands. It instead rasterizes the contents in place and stores them as an ID2D1Bitmap. Because the contents are rasterized, these interop points do not maintain high fidelity.

GDI: The command sink interface does not support Get/ReleaseDC() calls. When a call to ID2D1GdiInteropRenderTarget::ReleaseDC is made, Direct2D renders the contents of the updated region into a D2D1Bitmap. This will be replayed as an aliased DrawBitmap call with a copy composite mode. To rasterize the bitmap at the correct DPI, at the time of playback of the commands, whatever DPI value is set using the SetDPI() function is used. This is the only case where the sink respects the SetDPI() call.

DX: Direct3D cannot render directly to the command list. To render Direct3D content in this case, the application can call DrawBitmap with the ID2D1Bitmap backed by a Direct3D surface.

Requirements

Requirement Value
Minimum supported client Windows 8 and Platform Update for Windows 7 [desktop apps | UWP apps]
Minimum supported server Windows Server 2012 and Platform Update for Windows Server 2008 R2 [desktop apps | UWP apps]
Target Platform Windows
Header d2d1_1.h

See also

Command List

ID2D1Bitmap

ID2D1Image

Printing and Command Lists