DirectX-Specs

D3D12: PIX Markers

v0.07 10/12/2026


Contents


Summary

As of 2025, PIXEvents provides APIs to instrument your game, labeling regions of CPU or GPU work and marking important occurrences. Common APIs include PixBeginEvent, PixEndEvent, and PixSetMarker which internally call ID3D12GraphicsCommandList::BeginEvent, ID3D12CommandQueue::BeginEvent, ID3D12GraphicsCommandList::EndEvent ID3D12CommandQueue::EndEvent, ID3D12GraphicsCommandList::SetMarker and ID3D12CommandQueue::SetMarker depending on the context.

The limitation of these APIs is that they operate only at the runtime level and do not propagate to the driver. As a result, these markers are absent in DX dump files, making it difficult to trace the marker hierarchy that led to a GPU crash or TDR.

This proposal introduces a new D3D12 functionality that adds new APIs to configure D3D12 runtime to allow PIX markers and device object names to reach the driver. By doing so, these markers and device object names can be included in DX dump files for postmortem debugging and made accessible to IHV tools at the driver level—something previously impossible. This driver-level visibility also allows IHVs to incorporate markers and device object names into profiling data.

This functionality is designed to integrate seamlessly with any Windows tooling, including IHV-specific tools, and is not exclusive to PIX. Additionally, PIX Events is available as an open-source software. If IHV tools need to decode marker data, they could use the PIX events decoder instead of creating their own decoder.

Proposed API

D3D12_USER_DEFINED_ANNOTATION_MODE

typedef
enum D3D12_USER_DEFINED_ANNOTATION_MODE
    {
        D3D12_USER_DEFINED_ANNOTATION_MODE_RUNTIME_ONLY = 0,
        D3D12_USER_DEFINED_ANNOTATION_MODE_DRIVER_RETAIL = 1,
    } D3D12_USER_DEFINED_ANNOTATION_MODE;

|Enum|Meaning| |—-|——-| |D3D12_USER_DEFINED_ANNOTATION_MODE_RUNTIME_ONLY| API does not make DDI call to UMD | |D3D12_USER_DEFINED_ANNOTATION_MODE_DRIVER_RETAIL| API makes DDI call to UMD |

ID3D12DeviceTools2

interface ID3D12DeviceTools2 : ID3D12DeviceTools1
{
    HRESULT SetUserDefinedAnnotationMode(D3D12_USER_DEFINED_ANNOTATION_MODE mode);
    D3D12_USER_DEFINED_ANNOTATION_MODE GetUserDefinedAnnotationMode();
};

ID3D12DeviceTools2 interface can be QueryInterface’d from an ID3D12Device object. This interface will always be supported by newer versions of D3D12 going forward.

SetUserDefinedAnnotationMode configures the behavior of ID3D12Object::SetName(LPCWSTR Name) and D3D12 marker APIs listed below.

Similar APIs exist for ID3D12CommandQueue and ID3D12VideoProcessCommandList.

This means that any configuration applied using ID3D12DeviceTools2 will apply to subsequent device children, such as ID3D12GraphicsCommandList, ID3D12CommandQueue and ID3D12VideoProcessCommandList, created using the device interface. If the annotation mode is modified after some device child objects have already been created, the new setting will only apply to device children that are created after the change. Previously created device children will continue using the annotation mode that was active at the time of their creation.

For ID3D12Object::SetName(LPCWSTR Name), it is important to note that only device children objects will make DDI calls to UMD.

SetUserDefinedAnnotationMode returns S_OK for a valid mode and E_INVALIDARG for an invalid mode, leaving the previous mode unchanged on failure.

By default, the runtime annotation mode is D3D12_USER_DEFINED_ANNOTATION_MODE_RUNTIME_ONLY.

GetUserDefinedAnnotationMode returns the currently active annotation mode.

D3D12_FEATURE_USER_DEFINED_ANNOTATION

D3D12_FEATURE_USER_DEFINED_ANNOTATION is added to define support check for this feature.

typedef struct D3D12_FEATURE_DATA_USER_DEFINED_ANNOTATION
{
    BOOL Supported;
} D3D12_FEATURE_DATA_USER_DEFINED_ANNOTATION;
typedef enum D3D12_FEATURE
{
    D3D12_FEATURE_D3D12_OPTIONS                         =  0,
    D3D12_FEATURE_ARCHITECTURE                          =  1, // Deprecated by D3D12_FEATURE_ARCHITECTURE1
    ...
    D3D12_FEATURE_USER_DEFINED_ANNOTATION               = 73,
} D3D12_FEATURE;

Setting DRIVER_RETAIL succeeds even without driver support. In this case, the runtime still copies and tracks marker data, but marker and naming APIs make no annotation DDI calls.

Marker Data Lifetime

The D3D12 runtime manages marker data by maintaining an internal copy whose lifetime is tied to the associated command allocator. When the command allocator is reset, all marker data linked to it is discarded. If the marker is set in the context of a command queue instead of a command list, its lifetime is instead bound to the command queue.

The runtime also maintains a mapping between each marker’s data and a unique identifier known as an AnnotationID. This AnnotationID is passed along with the marker data to the driver, which may utilize them as needed. The driver’s handling of this data is described in Proposed DDI section.

It’s important to note that the driver is responsible for managing the lifetime of data that’s passed through PFND3D12DDI_SET_NAME_0121.

Note that when the annotation mode is D3D12_USER_DEFINED_ANNOTATION_MODE_RUNTIME_ONLY, the runtime does not retain a copy of marker data. This is intentional to avoid the bookkeeping cost: since no marker AnnotationID is ever issued to the driver in this mode, the runtime has no need to map an AnnotationID back to marker data.

Thread Safety and Synchronization

Applications are responsible for synchronizing calls to SetUserDefinedAnnotationMode with device child object creation. The annotation mode is device specific mutable state that can be modified concurrently by multiple threads. For example, one thread may set the mode to D3D12_USER_DEFINED_ANNOTATION_MODE_DRIVER_RETAIL and create a command queue, while another thread sets the mode to D3D12_USER_DEFINED_ANNOTATION_MODE_RUNTIME_ONLY and create a command list. Although the intended behavior is for command queue marker APIs to be forwarded to the driver and command list marker APIs to be remain runtime-only, subsequent mode changes may occur before object creation completes, causing both objects to use the most recently set mode.

Proposed DDI

Command List DDIs

DDI rev 121 adds D3D12DDI_USER_DEFINED_ANNOTATION_FUNCS_0121.

//----------------------------------------------------------------------------------------------------------------------------------
// D3D12 PIX Markers
// Feature: D3D12DDI_FEATURE_0121_USER_DEFINED_ANNOTATION
// Version: D3D12DDI_FEATURE_VERSION_USER_DEFINED_ANNOTATION_0121_0
// Usermode DDI Min Version: D3D12DDI_SUPPORTED_0121
//
//----------------------------------------------------------------------------------------------------------------------------------

#define D3D12DDI_FEATURE_VERSION_USER_DEFINED_ANNOTATION_0121_0 1u
#define D3D12DDI_FEATURE_VERSION_USER_DEFINED_ANNOTATION_LATEST D3D12DDI_FEATURE_VERSION_USER_DEFINED_ANNOTATION_0121_0

// Command Queue
typedef VOID ( APIENTRY* PFND3D12DDI_COMMAND_QUEUE_BEGIN_EVENT_0121 )(
    D3D12DDI_HCOMMANDQUEUE,                     // in: Driver handle
    UINT Metadata,                              // in: Runtime marker format data version
    _In_reads_(Size) CONST VOID* pData,         // in: Pointer to runtime marker data
    UINT Size,                                  // in: Size in bytes of runtime marker data
    UINT64 AnnotationID);                       // in: ID mapping to runtime marker data

typedef VOID (APIENTRY* PFND3D12DDI_COMMAND_QUEUE_END_EVENT_0121 )(
    D3D12DDI_HCOMMANDQUEUE,                     // in: Driver handle
    UINT64 AnnotationID);                       // in: ID mapping to runtime marker data

typedef VOID ( APIENTRY* PFND3D12DDI_COMMAND_QUEUE_SET_MARKER_0121 )(
    D3D12DDI_HCOMMANDQUEUE,                     // in: Driver handle
    UINT Metadata,                              // in: Runtime marker format data version
    _In_reads_(Size) CONST VOID* pData,         // in: Pointer to runtime marker data
    UINT Size,                                  // in: Size in bytes of runtime marker data
    UINT64 AnnotationID);                       // in: ID mapping to runtime marker data

// Command List
typedef VOID (APIENTRY* PFND3D12DDI_COMMAND_LIST_SET_MARKER_0121 )(
    D3D12DDI_HCOMMANDLIST,                      // in: Driver handle
    UINT Metadata,                              // in: Runtime marker format data version
    _In_reads_(Size) CONST VOID* pData,         // in: Pointer to runtime marker data
    UINT Size,                                  // in: Size in bytes of runtime marker data
    UINT64 AnnotationID);                       // in: ID mapping to runtime marker data

typedef VOID (APIENTRY* PFND3D12DDI_COMMAND_LIST_END_EVENT_0121)(
    D3D12DDI_HCOMMANDLIST,                      // in: Driver handle
    UINT64 AnnotationID);                       // in: ID mapping to runtime marker data

typedef VOID (APIENTRY* PFND3D12DDI_COMMAND_LIST_BEGIN_EVENT_0121)(
    D3D12DDI_HCOMMANDLIST,                      // in: Driver handle
    UINT Metadata,                              // in: Runtime marker format data version
    _In_reads_(Size) CONST VOID* pData,         // in: Pointer to runtime marker data
    UINT Size,                                  // in: Size in bytes of runtime marker data
    UINT64 AnnotationID);                       // in: ID mapping to runtime marker data

// SetName
typedef VOID (APIENTRY* PFND3D12DDI_SET_NAME_0121)(
    D3D12DDI_HANDLE_AND_TYPE,                   // in: Driver handle and type
    _In_ LPCWSTR pName);                        // in: Pointer to name string

typedef struct D3D12DDI_USER_DEFINED_ANNOTATION_FUNCS_0121
{
    // Command Queue
    PFND3D12DDI_COMMAND_QUEUE_BEGIN_EVENT_0121  pfnCommandQueueBeginEvent;
    PFND3D12DDI_COMMAND_QUEUE_END_EVENT_0121    pfnCommandQueueEndEvent;
    PFND3D12DDI_COMMAND_QUEUE_SET_MARKER_0121   pfnCommandQueueSetMarker;

    // Command List
    PFND3D12DDI_COMMAND_LIST_BEGIN_EVENT_0121   pfnCommandListBeginEvent;
    PFND3D12DDI_COMMAND_LIST_END_EVENT_0121     pfnCommandListEndEvent;
    PFND3D12DDI_COMMAND_LIST_SET_MARKER_0121    pfnCommandListSetMarker;

    PFND3D12DDI_SET_NAME_0121                   pfnSetName;
} D3D12DDI_USER_DEFINED_ANNOTATION_FUNCS_0121;

Drivers are expected to embed runtime marker AnnotationIDs in GPU crash reports to enable the runtime to associate those IDs with corresponding marker data. This correlation allows the runtime to include relevant marker information in the crash dump. Access to runtime marker data is provided to drivers to support decoding by IHV tools. Drivers may disregard this data if such decoding is not required.

Unlike marker AnnotationIDs, device object names are optional and may be included only if the driver manages the associated device object name data.

Use Case Example

Application developers typically want different marker behavior between development and retail builds:

PIXEvents supports this split with two families of marker macros:

When the USE_PIX_RETAIL preprocessor symbol is defined, the non-retail macros (PIXBeginEvent, PIXEndEvent, PIXSetMarker) compile to no-ops. Only the PIX*Retail* variants make runtime calls.

The recommended configurations are:

Scenario USE_PIX_RETAIL defined? PIX APIs reaching the runtime D3D12_USER_DEFINED_ANNOTATION_MODE Result
Development build No Both PIX* and PIX*Retail* DRIVER_RETAIL All PIX markers are forwarded to the driver and available in DX dump files.
Retail build No Both PIX* and PIX*Retail* DRIVER_RETAIL All markers, including high-frequency development markers, are forwarded to the driver.
Retail build Yes Only PIX*Retail* RUNTIME_ONLY No markers are forwarded to the driver at runtime.
Retail build Yes Only PIX*Retail* DRIVER_RETAIL Only retail markers are forwarded to the driver and available in DX dump files. Non-retail markers are compiled out.

The intent of this design is that existing users of the PIX Event APIs need to make only minimal changes to opt into driver-visible markers in shipped titles.

D3DConfig Override

A new boolean option, ForceDriverRetailAnnotations, is added to D3DConfig to force D3D12_USER_DEFINED_ANNOTATION_MODE_DRIVER_RETAIL on every D3D12 device created on the system. This lets developer tools and IHVs collect driver-visible markers (and have them appear in DX dump files) without modifying or rebuilding the title.

Behavior:

Example usage from the command line:

# Force DRIVER_RETAIL on for all subsequently created D3D12 devices on the system.
d3dconfig device force-driver-retail-annotations=on

# Inspect current D3DConfig device settings (verifies the override is on).
d3dconfig device

# Turn the override back off when finished.
d3dconfig device force-driver-retail-annotations=off

Open Questions

Test Plan

Functional tests

Conformance tests

Covered by the D3DConf_12_PixMarkers HLK test class:

WARP support

WARP reports support for the PIX marker DDIs and logs the marker calls, but does not retain the marker data. If we expand WARP to produce real crash dumps in the future, we should look into retaining marker data inside WARP so it can be included.

Spec History

Version Date Details Author
v0.07 12 Oct 2026 Correct API/DDI declarations Henchhing Limbu (PIX)
v0.06 17 Jun 2026 Fix typos, and correct ID3D12DeviceTools2 heading Henchhing Limbu (PIX)
v0.05 01 Jun 2026 Clarify RUNTIME_ONLY marker data behavior, add development vs retail use case example, expand D3DConfig override section, and flesh out Test Plan and WARP support Henchhing Limbu (PIX)
v0.04 30 Jan 2026 Remove caps DDI calls and add multithreading synchronization Henchhing Limbu (PIX)
v0.03 20 Jan 2026 Flesh out DDIs and update them to pass device object name Henchhing Limbu (PIX)
v0.02 07 Jan 2026 Revise runtime configuration behavior Henchhing Limbu (PIX)
v0.01 03 Oct 2025 Initial draft spec Henchhing Limbu (PIX)