Donner SVG 0.8.0
0.8.0 ยท ebf353960.8.0 main
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 <chrono>
#include <functional>
#include <ostream>
#include "donner/gpu/DeviceLost.h"
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...

Namespaces

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

Typedefs

using donner::geode::GpuWaitSite = gpu::DeviceLostWaitSite
 Which bounded wait exceeded its deadline and declared the device lost. The runtime owns the enumeration because the condition belongs to the backend root, not to the Geode wrappers over it; see gpu::DeviceLostWaitSite.
using donner::geode::GeodeDeviceLostState = gpu::DeviceLostState
 Shared device-lost flag of one backend root, observed and published by every Geode context over it and by a host embedder's own device-lost callback. Owned by the runtime; see gpu::DeviceLostState.

Enumerations

enum class  donner::geode::GpuWaitResult {
  Complete ,
  TimedOut ,
  DeviceLost
}
 Outcome of a bounded GPU wait. More...

Functions

std::ostream & donner::geode::operator<< (std::ostream &os, GpuWaitResult value)
 Ostream output operator, e.g. TimedOut.
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.
bool donner::geode::DeclareDeviceLost (DeviceLostState &state)
 Declares a state lost with no wait to attribute it to; see gpu::DeclareDeviceLost.
bool donner::geode::DeclareDeviceLostAfterWaitTimeout (DeviceLostState &state, DeviceLostWaitSite site, std::chrono::milliseconds elapsed)
 Declares a state lost because a bounded wait gave up; see gpu::DeclareDeviceLostAfterWaitTimeout.

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).
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 and ostream 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 wait gave up without the condition being observed: a queue-idle wait because the work stopped progressing, other waits because their deadline expired. 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.

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.

◆ operator<<()

std::ostream & donner::geode::operator<< ( std::ostream & os,
GpuWaitResult value )

Ostream output operator, e.g. TimedOut.

Parameters
osOutput stream.
valueValue to output.

Variable Documentation

◆ kDefaultGpuWaitTimeout

std::chrono::milliseconds donner::geode::kDefaultGpuWaitTimeout {5000}
inlineconstexpr

Default bound for waits that previously blocked without limit (teardown drains, inter-submit serialization, editor readback maps).

A wait for submitted work measures it as time without progress, not as a budget for the whole wait: the awaited work completes only after everything queued ahead of it, and a slow device can take far longer than this to get through a long backlog while still finishing command buffers. A healthy device finishes some command buffer well within the bound, so it only trips when the device has effectively hung.