Donner SVG 0.8.0-pre
SVG editor and embeddable C⁠+⁠+⁠20 engine.
Loading...
Searching...
No Matches
GeodeGpuWait.h File Reference

Bounded CPU-side waits on GPU progress, and the shared device-lost flag. More...

#include <atomic>
#include <chrono>
#include <cstdint>
#include <functional>
Include dependency graph for GeodeGpuWait.h:
This graph shows which files directly or indirectly include this file:

Classes

struct  donner::geode::GpuWaitTestHooks
 Test seams for BoundedGpuWait. Production callers pass none; tests inject a fake clock and a sleep recorder so timeout behavior is verified deterministically and without real sleeping. More...
struct  donner::geode::GeodeDeviceLostState
 Shared device-lost flag. More...

Namespaces

namespace  donner
 Top-level Donner namespace, which is split into different sub-namespaces such as donner::svg and donner::css.

Enumerations

enum class  donner::geode::GpuWaitResult {
  Complete ,
  TimedOut ,
  DeviceLost
}
 Outcome of a bounded GPU wait. More...
enum class  donner::geode::GpuWaitSite : std::uint8_t {
  None ,
  ReadbackMap ,
  QueueIdle
}
 Which bounded wait exceeded its deadline and declared the device lost. More...

Functions

bool donner::geode::DeclareDeviceLost (GeodeDeviceLostState &state)
 Declare state lost with no wait to attribute it to.
bool donner::geode::DeclareDeviceLostAfterWaitTimeout (GeodeDeviceLostState &state, GpuWaitSite site, std::chrono::milliseconds elapsed)
 Declare state lost because a bounded wait at site exceeded its deadline after elapsed.
GpuWaitResult donner::geode::BoundedGpuWait (const std::function< bool()> &pollOnce, std::chrono::microseconds timeout, std::chrono::microseconds pollInterval=kGpuWaitPollInterval, const GpuWaitTestHooks &testHooks={})
 Repeatedly invoke pollOnce until it returns true or timeout expires.

Variables

constexpr std::chrono::milliseconds donner::geode::kDefaultGpuWaitTimeout {5000}
 Default bound for waits that previously blocked without limit (teardown drains, inter-submit serialization, editor readback maps). Generous: a healthy device completes these in microseconds to milliseconds, so the bound only trips when the driver has effectively hung.
constexpr std::chrono::milliseconds donner::geode::kReadbackMapTimeout {10000}
 Bound for snapshot readback map waits. Matches the long-standing readback deadline: snapshot consumers tolerate up to 10 seconds under heavily loaded parallel test runs before declaring the device unresponsive.
constexpr std::chrono::microseconds donner::geode::kGpuWaitPollInterval {100}
 Poll cadence for non-blocking wait loops. The 100 us cadence bounds completion-detection latency without measurable CPU cost; the snapshot readback path was tuned to this cadence and the perf ceilings assume it.

Detailed Description

Bounded CPU-side waits on GPU progress, and the shared device-lost flag.

A hung GPU driver can leave a fence or buffer-map wait blocked forever, in the worst case in uninterruptible kernel sleep. Donner cannot fix drivers, but no thread the application relies on may block unboundedly on the GPU: a hung device must surface as a detectable device-lost condition instead of a hung process. Every native CPU-blocks-on-GPU wait in the Geode stack routes through this header so the timeout policy lives in exactly one place.

This header is deliberately WebGPU-free (chrono + functional only) so the wait loop can be unit tested without a GPU via the injectable clock and sleep hooks.

Enumeration Type Documentation

◆ GpuWaitResult

enum class donner::geode::GpuWaitResult
strong

Outcome of a bounded GPU wait.

Enumerator
Complete 

The awaited condition was observed before the deadline.

TimedOut 

The deadline expired without the condition being observed. Callers treat this as evidence of a hung device and declare the device lost.

DeviceLost 

The device was already marked lost; no wait was performed.

◆ GpuWaitSite

enum class donner::geode::GpuWaitSite : std::uint8_t
strong

Which bounded wait exceeded its deadline and declared the device lost.

A hung device costs the full timeout wherever it is first waited on, and the two waits have very different budgets and callers, so "the device was declared lost" is not actionable on its own: a readback-map timeout points at buffer-map delivery, a queue-drain timeout points at submitted work never retiring. Recording which one tripped keeps that distinction in the diagnostics a failure report is assembled from.

Enumerator
None 

No bounded wait has timed out. A device lost with this site was reported by the driver's device-lost callback, not by a deadline.

ReadbackMap 

A buffer-map wait for GPU-to-CPU readback (snapshot or surface capture).

QueueIdle 

A wait for the GPU queue to drain (teardown, inter-submit serialization).

Function Documentation

◆ BoundedGpuWait()

GpuWaitResult donner::geode::BoundedGpuWait ( const std::function< bool()> & pollOnce,
std::chrono::microseconds timeout,
std::chrono::microseconds pollInterval = kGpuWaitPollInterval,
const GpuWaitTestHooks & testHooks = {} )

Repeatedly invoke pollOnce until it returns true or timeout expires.

pollOnce must be non-blocking: one device poll (or callback-flag check) that returns true when the awaited condition has been observed. The loop never blocks inside the driver, so a hung device costs at most timeout plus one pollInterval instead of hanging the calling thread forever.

The happy path costs one pollOnce call and one clock read, so wrapping an already-complete wait adds no measurable overhead.

Parameters
pollOnceNon-blocking poll; returns true when the wait is over.
timeoutTotal time budget for the wait. Taken in microseconds because the readback wait slices below a millisecond, and a budget rounded up to a whole millisecond would coarsen the poll cadence the readback path is tuned to.
pollIntervalSleep between polls while the condition is pending.
testHooksOptional clock/sleep overrides for deterministic tests.
Returns
Complete if pollOnce returned true, TimedOut otherwise.

◆ DeclareDeviceLost()

bool donner::geode::DeclareDeviceLost ( GeodeDeviceLostState & state)

Declare state lost with no wait to attribute it to.

For losses the driver reports: there is no deadline behind them, so timedOutSite stays None and says exactly that.

Returns
True when this call performed the false-to-true transition, so a caller can log the cause exactly once.

◆ DeclareDeviceLostAfterWaitTimeout()

bool donner::geode::DeclareDeviceLostAfterWaitTimeout ( GeodeDeviceLostState & state,
GpuWaitSite site,
std::chrono::milliseconds elapsed )

Declare state lost because a bounded wait at site exceeded its deadline after elapsed.

The attribution is written only when this call is the one that declares the loss. Two other writers reach the same flag and neither may claim the site: a later bounded wait, which expires because the device is ALREADY hung (a consequence of the loss, never its cause), and the driver's device-lost callback, which has no wait to name. Deriving the claim from the flag's own transition covers both without a check-then-set window - reading the flag and then storing the site would let a driver-reported loss landing in between be relabelled as a wait timeout, which is the one misattribution an empty site exists to rule out.

Parameters
stateShared device-lost record.
siteWhich bounded wait expired.
elapsedWall time that wait spent before giving up.
Returns
True when this call performed the false-to-true transition.