Causes and Fixes for D3D12_ERROR_DEVICE_REMOVED
The D3D12_ERROR_DEVICE_REMOVED error occurs in DirectX
12 applications when the graphics processing unit (GPU) stops
communicating with the system, effectively detaching the hardware from
the rendering pipeline. This article explores the primary technical
triggers behind this failure—including Timeout Detection and Recovery
(TDR) events, invalid API calls, GPU memory faults, and driver
instability. It also outlines the concrete debugging methodologies used
to diagnose the issue, such as Device Removed Extended Data (DRED), and
provides step-by-step procedures for handling runtime recovery within
your engine.
Primary Causes of Device Removal
When DirectX 12 returns D3D12_ERROR_DEVICE_REMOVED, the
device is no longer usable. The root causes generally fall into the
following categories:
- GPU Timeout Detection and Recovery (TDR): The Windows OS monitors the GPU to ensure it remains responsive. If a compute dispatch or complex rendering pass takes longer than the TDR threshold (default is 2 seconds), the OS preemptively resets the driver to prevent the display from freezing.
- Invalid API Usage and Unsynchronized Access: Writing to unmapped or freed memory, access violations inside shader code (such as out-of-bounds reads or writes to Unordered Access Views), or resource state transition errors frequently cause low-level hardware page faults.
- Out-of-Memory (OOM) Conditions: Failing to budget and manage local VRAM can force the OS to evict resources. In severe allocation spikes where the memory manager cannot satisfy demands, the runtime triggers a device removal.
- Physical Disconnection or Driver Updates: External GPUs (eGPUs) over Thunderbolt, dynamic GPU switching on laptops, or on-the-fly driver updates during application runtime physically or logically remove the hardware instance.
- Hardware Instability and Overclocking: Excessive GPU core/memory clock speeds, thermal throttling, or inadequate power delivery can trigger transient hardware errors that force the driver to crash.
Diagnosing the Exact Failure Reason
To determine why the device was removed, developers must use the diagnostic APIs built into DirectX 12:
1. Call
GetDeviceRemovedReason
Immediately after an API call fails with
D3D12_ERROR_DEVICE_REMOVED, invoke
ID3D12Device::GetDeviceRemovedReason(). This returns an
HRESULT detailing the failure mode:
DXGI_ERROR_DEVICE_HUNG: The GPU failed to execute commands in the allotted time (TDR).DXGI_ERROR_DEVICE_RESET: The GPU received an invalid command sequence or suffered an internal crash.DXGI_ERROR_DRIVER_INTERNAL_ERROR: The driver encountered an unhandled exception.DXGI_ERROR_INVALID_CALL: The application made a malformed API call that caused fatal state corruption.E_OUTOFMEMORY: The driver or GPU ran out of address space or physical memory.
2. Enable Device Removed Extended Data (DRED)
DRED is the standard diagnostic tool for post-mortem analysis in D3D12. It records breadcrumbs of executed GPU commands and logs page fault allocations.
To enable DRED before creating the device:
Microsoft::WRL::ComPtr<ID3D12DeviceRemovedExtendedDataSettings> pDredSettings;
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&pDredSettings))))
{
pDredSettings->SetAutoBreadcrumbsEnablement(D3D12_DRED_ENABLEMENT_FORCED_ON);
pDredSettings->SetPageFaultEnablement(D3D12_DRED_ENABLEMENT_FORCED_ON);
}When a crash occurs, query ID3D12Device5 for the
ID3D12DeviceRemovedExtendedData interface to retrieve the
auto-breadcrumb trail (showing the exact command list and draw call that
hung) and the page fault address matching virtual allocation
records.
3. Use the Debug Layer and GPU-Based Validation (GBV)
Enable the D3D12 Debug Layer alongside GPU-Based Validation in debug
builds using
ID3D12Debug1::SetEnableGPUBasedValidation(TRUE). GBV
intercepts shader resource bindings and tracks descriptor table errors
directly on the GPU, identifying invalid accesses before they trigger
hard TDRs.
How to Recover from the Error
DirectX 12 does not support "in-place" recovery. Once a device is removed, all interfaces associated with that device become invalid. Recovery requires a complete teardown and re-creation of the rendering infrastructure.
Step 1: Detect and Log
Monitor your frame execution loop—specifically fence synchronization
checks and IDXGISwapChain::Present calls. When an operation
returns DXGI_ERROR_DEVICE_REMOVED or
DXGI_ERROR_DEVICE_RESET, halt rendering passes immediately
and log the output of GetDeviceRemovedReason().
Step 2: Release All Hardware-Dependent Resources
All resources bound to the destroyed device must be destroyed in the correct order. You must release:
- Command queues, command allocators, and command lists.
- Descriptor heaps, root signatures, and pipeline state objects (PSOs).
- Vertex/index buffers, textures, dynamic upload buffers, and render targets.
- Swap chain back buffers (release references before recreating the swap chain).
- The
ID3D12Deviceinterface itself.
Step 3: Recreate the Device and Core Infrastructure
- Call
CreateDXGIFactory2to refresh the DXGI adapter enumeration list. - Select an appropriate hardware adapter
(
IDXGIAdapter). - Call
D3D12CreateDeviceto instantiate a fresh device. - Recreate the command queues and the swap chain (or call
IDXGISwapChain::ResizeBuffersif the swap chain interface remained intact on the existing factory).
Step 4: Reload Assets and Rebuild State
- Re-allocate descriptor heaps and pipeline state objects.
- Re-upload textures, meshes, and constant buffers from system memory cache or local disk storage back to GPU memory.
- Reset engine frame counters and fence values to start command execution cleanly.
Prevention Strategies
- Split Compute Workloads: Break massive compute passes (e.g., ray tracing, fluid simulations, procedural generation) into smaller sub-dispatches to stay well clear of the OS-enforced 2-second TDR window.
- Monitor VRAM Usage: Implement
IDXGIAdapter3::QueryVideoMemoryInfoto actively monitor memory pressure and dynamically downgrade asset quality before hitting out-of-memory states. - Enforce Resource State Correctness: Validate that resource transitions are explicit and complete, eliminating race conditions between read and write operations across concurrent command queues.