DeviceLossMonitor

One detector for a removed GPU device, for every QRhi of the process.

Inherits QObject

In the namespace rhi. Declared in src/libs/librhi/rhi/DeviceLossMonitor.hpp.

Detailed description

gpu-timeout-recovery §GTR-D2. On 2026-10-08 a GPU timeout removed the Direct3D 12 device under construct, and nothing in construct knew: Qt's Direct3D 12 backend marks a loss only when a swapchain's Present() fails (§GTR-F5.2), so every offscreen QRhi kept rendering into a removed device for six minutes. On mathilde64 an offscreen QRhi kept isDeviceLost() false even after a frame that failed on the removed device (§GTR-F6 P4).

Each QRhi that construct creates or adopts registers here with an owner name. On Direct3D 12 the monitor creates one fence on each distinct device and asks for an event when it reaches UINT64_MAX: a removal signals every fence of the device to that value, and the event fired 0 ms after RemoveDevice() in P4. A thread-pool wait on the event queues the loss to the monitor's thread. An owner that sees a failure reports it, and the monitor asks the device, which also covers the other backends through QRhi::isDeviceLost().

The monitor emits deviceLost() once per device, with every owner on it. A fence holds a reference to its device, and Direct3D 12 makes no new device on an adapter while the removed one has a holder (§GTR-F6 P5), so the monitor drops its own fence and wait first, before it emits.

Member function documentation

deviceKey

[static] void *DeviceLossMonitor::deviceKey(QRhi *rhi)

The key of rhi's device: the native device on Direct3D 12, so that QRhis sharing a device share a key; the QRhi elsewhere.

isLost

bool DeviceLossMonitor::isLost(QRhi *rhi) const

Returns true once the device of rhi is reported lost.

isStopped

bool DeviceLossMonitor::isStopped(void *deviceKey) const

Returns true while a HardStop holds deviceKey.

ownersOf

QStringList DeviceLossMonitor::ownersOf(QRhi *rhi) const

The owners registered on the device of rhi.

registerRhi

int DeviceLossMonitor::registerRhi(QRhi *rhi, const QString &owner, rhi::DeviceLossMonitor::Role role = Role::Offscreen, std::function<void ()> release = {})

Registers rhi under owner and returns the registration id.

role says whether the QRhi is an offscreen owner's or a window's. release, when set, is called on the monitor's thread when the device is lost. The owner then releases rhi on its own thread and ends the registration. Returns 0 when rhi is null.

The first registration of a Direct3D 12 device sets up its fence event. A device that is already removed is reported at once.

reportFailure

bool DeviceLossMonitor::reportFailure(QRhi *rhi)

An owner saw a failure on rhi; the monitor asks the device.

Returns true when the device is lost, and reports the loss.

reportLost

void DeviceLossMonitor::reportLost(QRhi *rhi, const QString &reason)

An owner knows rhi's device is lost, for reason.

reportLostKey

void DeviceLossMonitor::reportLostKey(void *key)

The fence's wait, or a registration of a removed device, reports key: the reason comes from the device.

unregisterRhi

void DeviceLossMonitor::unregisterRhi(int id)

Ends registration id; the last one on a device drops the monitor's fence and wait on it.

waitForRecovery

bool DeviceLossMonitor::waitForRecovery(void *deviceKey, int timeoutMs)

Blocks until the recovery of deviceKey passed its release step, or timeoutMs. Returns true when a new QRhi can be made.

A capture or export renderer on its own thread calls this between the failed render and its one retry. Without it the retry's create raced the other owners' release: Direct3D 12 refused it while they held the lost device, and the backend ladder put the retry on Vulkan, which the incident's second capture did (§GTR-F1).

In this section