Donner SVG 0.8.0
0.8.0 ยท ebf353960.8.0 main
SVG editor and embeddable C⁠+⁠+⁠20 engine.
Loading...
Searching...
No Matches
donner::geode::GeodeDevice Class Reference

Owns a logical Geode context over a selected GPU runtime device. More...

#include "donner/svg/renderer/geode/GeodeDevice.h"

Classes

struct  ReadbackStats
 Readback timing, completion, loss, cancellation, and resource counters. More...
struct  SceneBatchBindGroupKey
 Key identifying a scene-batch bind group by its exact buffer bindings: the shared batch uniform allocation, the geometry slab chunk, and the record span. More...

Public Types

enum class  SnapshotReadbackPhase {
  WaitingForContext ,
  ContextAcquired ,
  MapRequested
}
 Explicit capture phases exposed only for deterministic protocol tests.

Public Member Functions

 ~GeodeDevice ()
 Destructor releases logical resources before their runtime device and selected root. Native builds wait, bounded by lack of progress, for this context's submitted work, and a declared loss skips those waits; a Vulkan runtime device still proves its own submissions complete when it is destroyed. WebAssembly builds do not wait.
 GeodeDevice (const GeodeDevice &)=delete
GeodeDevice & operator= (const GeodeDevice &)=delete
 GeodeDevice (GeodeDevice &&)=delete
GeodeDevice & operator= (GeodeDevice &&)=delete
uint32_t maxTextureDimension2D () const
 Maximum supported width or height of a 2D texture on this device.
GpuWaitResult waitForQueueIdle (std::chrono::milliseconds stallBound=kDefaultGpuWaitTimeout) const
 Wait, bounded by lack of progress, for all submitted GPU work to complete.
void setQueueWaitResultForTesting (std::optional< GpuWaitResult > result)
 Overrides one queue-idle result while preserving its loss side effects. Test seam.
bool isDeviceLost () const
 True once this device has been declared lost, either by its backend or by a bounded GPU wait exceeding its deadline. Sticky: never resets. Once lost, rendering output is undefined, snapshots return empty bitmaps promptly, and this context's teardown skips its queue-idle waits; a Vulkan runtime device still proves its own submissions complete when it is destroyed.
bool isBoundToCreatingThread () const
 Whether this device may only be used on the thread that created it: true on the browser backend, whose objects belong to the worker that made them, and false on every backend whose devices any thread may drive. A cache of idle devices hands a bound device back only to the thread that created it.
void markDeviceLost (const char *reason) const
 Declare this device lost with no wait to attribute it to. Idempotent; the first call logs reason. Called when a frame's or a filter's commands cannot be closed, submitted, or restored, and available to embedders whose own device-lost signal is not shared through the selected root. Bounded waits that give up use markDeviceLostAfterWaitTimeout instead. Const because observers treat the flag as shared diagnostic state and waits that discover a hang run through const accessors.
void markDeviceLostAfterWaitTimeout (GpuWaitSite site, std::chrono::milliseconds elapsed, const char *reason) const
 Declare this device lost because a bounded wait exceeded its deadline, recording which wait it was and how long it actually ran.
void setSnapshotReadbackBudgetForTesting (std::chrono::milliseconds budget)
 Override the total capture budget for deterministic cancellation/deadline tests.
void setSnapshotReadbackHookForTesting (std::function< void(SnapshotReadbackPhase)> hook)
 Install a capture-phase test hook; it may be called concurrently by capture waiters.
void setSnapshotCaptureRuntimeHookForTesting (std::function< void(gpu::Device &)> hook)
 Test-only access to the capture runtime while its lease is held, before it submits work. Set only while captures are quiescent; the callback must not retain the reference past the capture context's lifetime.
void recordReadback (bool usedTimedWaitAny, int pollIterations)
 Record one readback buffer-map wait from a renderer sharing this device, whether or not the map completed.
ReadbackStats consumeReadbackStats ()
 Consume aggregate readback diagnostics for all renderers sharing this device.
const std::shared_ptr< GeodeDeviceLostState > & lostState () const
 The sticky loss condition of the physical root this context renders through, shared with every other context over that root and with the runtime devices driving it. Retained rather than borrowed because a backend device-lost callback can outlive the context that registered it.
std::shared_ptr< GeodePhysicalDeviceOwner > physicalDeviceOwner () const
 Shared owner of the selected backend root and the runtime device the first context over it renders through, retained by every logical context over that root. Pass it to CreateOverPhysicalDeviceOwner for a sibling context with a runtime device of its own.
gpu::TextureFormat textureFormat () const
 Render-target texture format, chosen by the caller or defaulted to RGBA8Unorm.
void deferDestroy (gpu::BindGroup bindGroup)
 Enqueue a bind group for deferred destruction.
bool deferDestroyTextureBacking (gpu::Texture &&texture)
 Transfer owned texture backing to this context's thread-safe retirement mailbox.
bool deferDestroyTextureBackingAfterSerial (gpu::Texture &&texture, uint64_t serial)
 Retain a failed frame's owned texture until this context has completed serial, then destroy its backing instead of recycling it with any unsubmitted writes.
void drainFencedTextureBackings ()
 Retire completed failed-frame textures without blocking on GPU progress.
std::size_t pendingFencedTextureBackings () const
 Number of failed-frame textures still awaiting a submission fence.
void drainDeferredTextureBackings ()
 Destroy queued texture backing on the owning rendering context or during exclusive teardown.
const std::shared_ptr< GeodeHandleRetirement > & handleRetirement () const
 Where state kept for this context on another thread's behalf - a document's resident slabs, say - hands back this context's buffers and bind groups when it is destroyed, so they are released on this context's thread (see GeodeHandleRetirement).
void releaseRetiredHandles ()
 Releases the handles other threads retired to this context. Call on this context's thread; the renderer does at every frame boundary.
GeodeHandleRetirement::HeldCounts retiredHandleCountsForTesting () const
 Handles retired to this context and not yet released. Test accessor.
bool retirementOutlivesOwnedRuntimeDeviceForTesting () const
 Whether this context's retirement is destroyed after the runtime device it created, as handleRetirement requires: true when handleRetirement_ is declared before ownedRuntimeDevice_. Test accessor.
void drainDeferredDestroys ()
 Drop all deferred-destroy handles, releasing their GPU resources.
void pollIdle ()
 Nonblocking owner-thread maintenance after a frame or while the renderer is idle. Drains cross-thread mailboxes, pumps callback-driven backends once, and releases completed work. No new submission or queue wait is required.
bool hasIdleWork () const
 Whether idle maintenance can still free resources when a completion arrives. Owner-thread only; event loops may use it to schedule a short maintenance wake instead of rendering.
void setIdleWakeCallback (std::function< void()> callback)
 Posts a cheap wake when a cross-thread retirement arrives. Callbacks must not reenter this context and must be cleared before their event loop is destroyed.
std::size_t deferredTextureDestroyCountForTesting () const
 Number of texture backings waiting for the next frame-boundary destroy pass. Exposed to pin resource-retirement behavior in renderer regression tests.
GpuWaitResult waitForSnapshotCaptureIdleForTesting (std::chrono::milliseconds timeout=kDefaultGpuWaitTimeout)
 Waits until the snapshot capture context's queue has no submitted work left, so a test can check what the owner's next release point frees once every capture has finished on the GPU, without polling for it.
const gpu::BindGroup * findSceneBatchBindGroup (const SceneBatchBindGroupKey &key)
 Look up a cached scene-batch bind group. Returns a borrowed handle (valid while the cache entry lives), or an empty handle on miss. A hit refreshes the entry to most-recently-used, so eviction at the cap drops the coldest entry rather than the oldest-inserted one - with more than the cap of live groups, pure insertion order would evict the hottest steady-state entry every frame.
const gpu::BindGroup & storeSceneBatchBindGroup (const SceneBatchBindGroupKey &key, gpu::BindGroup group)
 Store a scene-batch bind group under key, taking ownership of the +1 handle. At the cap, the OLDEST entries are evicted one at a time rather than the whole cache being dropped: the cache is device-wide and a key belongs to one document's buffers, so wholesale clearing punished the live document for documents that had already been torn down, and a steady frame then rebuilt every batch group it had just been using. Insertion order puts those dead entries first. Recorded command buffers keep their own references, so dropping the cache's handle mid-frame is safe either way.
uint64_t deviceId () const
 Process-unique identity for this device instance, assigned at construction from a monotonic counter (never reused, starts at 1).
void setCounters (GeodeCounters *counters)
 Install a GeodeCounters struct for this device.
GeodeCounters * counters () const
 Non-owning pointer to the installed counters, or null.
void countBuffer () const
 Record one buffer creation in lifetime and attached frame counters.
void countBindGroup () const
 Record one bind-group creation in the attached frame counters.
void countTexture () const
 Record one texture creation in lifetime and attached frame counters.
uint64_t lifetimeTextureCreates () const
 Cumulative number of countTexture() calls since this GeodeDevice was created. Does not account for textures released back into a pool - it is an allocation-site counter, not a live-count.
void countTextureRelease () const
 Record that this context's runtime device gave up its ownership of a texture allocation.
uint64_t lifetimeTextureReleases () const
 Texture allocations whose ownership this context's runtime device has given up since the context was created (see gpu::DeviceObserver::onTextureReleased), on every backend. It excludes the snapshot-capture context, whose creations lifetimeTextureCreates() includes, so creates minus releases is not a live count.
uint64_t lifetimeBufferCreates () const
 Cumulative number of countBuffer() calls since this GeodeDevice was created. Same caveat as lifetimeTextureCreates().
void countSubmit () const
 Record one queue submission in the attached frame counters.
void countCommandBuffers (uint64_t count) const
 Record the command buffers one submission carried.
void countPathEncode () const
 Record one path encoding in the attached frame counters.
void countDraws (uint64_t count) const
 Record the draws a submission counted (see gpu::DeviceObserver::onSubmitted).
void countPipelineSwitch () const
 Record one pipeline switch in the attached frame counters.
void countBufferWrite (uint64_t bytes) const
 Record one runtime buffer write of bytes payload bytes.
void countTextureWrite (uint64_t bytes) const
 Record one runtime texture write of bytes payload bytes.
uint64_t beginFrameGeneration ()
 Open a frame on this device and return its generation.
void endFrameGeneration (uint64_t generation)
 Close a generation opened by beginFrameGeneration. Unknown values are ignored, so a renderer that never opened one (no-op mode) is safe.
uint64_t oldestOpenFrameGeneration () const
 Oldest generation whose frame has not closed yet, or ~0 when no frame is open. Anything a generation at or after this touched may still be read by an unsubmitted draw.
bool frameStampClaimed (uint64_t stamp) const
 True when a resource stamped with stamp (a generation minted by beginFrameGeneration) may still be read by a frame that has not submitted: some open frame is at or before the stamp, so a recorded draw in that frame can reference the stamped bytes, and every queue write in a frame lands before every draw in its submit.
void countGlyphResidencyHit () const
 Record one glyph occurrence served from an already-resident outline.
void countGlyphResidencyUpload () const
 Record one unique glyph outline encoded and made resident.
void countGlyphResidencyEvictions (uint64_t count) const
 Record count cached glyph outlines dropped to stay inside the budget.
const std::shared_ptr< std::atomic< int64_t > > & residentBytesGauge () const
 Shared live-resident-bytes gauge for GPU residence. Co-owned with each GeodeResidentSlot's buffer so resident-memory accounting stays lifetime-safe even if a document (and its ECS registry) outlives this device. Lazily created on first access. GeoEncoder bumps it when a slot gains residence; the slot decrements it on reset / destruction (geometry change or document teardown), which is the eviction signal for "many distinct documents".
int64_t liveResidentBytesForTesting () const
 Current live resident-geometry bytes across every GeodeResidentSlot buffer created against this device. Zero at construction and after all resident documents are torn down; used by eviction tests.
bool isVulkan () const
 True when the active native backend is Vulkan. GeodeFilterEngine uses this to force inter-pass serialization that eliminates a nondeterministic cross-submit storage-write -> sampled-read visibility race observed on Arc Vulkan. Metal returns false and keeps the fast multi-submit path.
gpu::Device & runtimeDevice () const
 This context's GPU runtime device: the owner of its handle tables, submission serials, and resource retirement. Renderer services that need only the runtime contract take this instead of naming the concrete backend type.
const GeodeGpuContext & gpuContext () const
 The recording context Geode's encoders record a frame against: this device's GPU runtime device, its shared bind-slot resources, and its counter sinks. Wired once with the shared pipelines and owned here, so it lives exactly as long as this device does.
gpu::DeviceObserver & runtimeCounterObserverForTesting () const
 The observer this context installs on its own runtime device, on every backend.
Shared render / compute pipelines (issue #575 fix)

The shared bind-slot resources - 1x1 dummy pattern texture and view, 1x1 full-coverage clip-mask texture and view, their samplers, a one-element identity instance record, and a zero-filled gradient paint block - are reached through gpuContext.

RendererGeode once constructed these pipeline objects per renderer instance, exhausting the GPU memory budget in image-comparison runs (issue #575). Ownership here keeps one fixed set per GeodeDevice instead.

Every renderer that talks to this device shares the same pipeline objects; their state is intentionally immutable after construction (no per-draw mutation), so concurrent use from sibling renderers is safe as long as submissions are serialized by the selected runtime device.

GeodePipeline & pipeline () const
 Slug solid-fill render pipeline.
GeodeGradientPipeline & gradientPipeline () const
 Slug gradient-fill render pipeline.
GeodeImagePipeline & imagePipeline () const
 Image-blit render pipeline (used by GeoEncoder::drawImage and the pattern / layer composition path).
GeodeMaskPipeline & maskPipeline () const
 Clip-path mask render pipeline. Built lazily on first access rather than eagerly at device creation, matching the prior per-encoder lazy path - most documents don't use <clipPath> and the production WASM path avoids the cost.
GeodeFilterEngine & filterEngine () const
 GPU filter-graph executor. Owns ~15 compute pipelines for SVG filter primitives.
GeodeCheckerboardPipeline & checkerboardPipeline () const
 Framebuffer checkerboard underlay pipeline used by the editor's direct presentation path. Built lazily on first access - only the editor draws it, so headless/WASM consumers never pay the compile cost.
GeodeCheckerboardPipeline & checkerboardUnderlayPipeline () const
 Destination-over variant of checkerboardPipeline, for targets that already hold composed premultiplied content and need the checkerboard placed underneath it. Built lazily and independently of the replace-blend pipeline, so a consumer only pays for the variant it actually draws.

Static Public Member Functions

static std::unique_ptr< GeodeDevice > CreateHeadless (gpu::TextureFormat textureFormat=gpu::TextureFormat::RGBA8Unorm)
 Create a headless GeodeDevice.
static std::unique_ptr< GeodeDevice > CreateOverSelectedRoot (std::shared_ptr< GeodeGpuRoot > root, gpu::TextureFormat textureFormat)
 Creates the first logical context over a backend root the caller already selected.
static std::unique_ptr< GeodeDevice > CreateOverPhysicalDeviceOwner (std::shared_ptr< GeodePhysicalDeviceOwner > physicalDevice, gpu::TextureFormat textureFormat)
 Creates another logical context over the selected physical owner.
static int headlessCreationCountForTesting ()
 Number of CreateHeadless calls made so far in this process. Each headless creation stands up a full physical GPU root, so hot paths must share one device instead of re-creating; tests pin that sharing by asserting this count stays flat across repeated operations.
static uint64_t AllocateBufferId ()
 Allocate a process-unique identity for a GPU buffer handle, from a monotonic counter that starts at 1 and is never reused.

Friends

class svg::RendererGeodeTextureSnapshot

Detailed Description

Owns a logical Geode context over a selected GPU runtime device.

GeodeDevice is the entry point to the Geode rendering backend. In headless mode it selects the platform's GPU root (native Metal or Vulkan, or the browser GPU runtime in WebAssembly builds) and creates a device without window system integration.

A host that selects a presentation root creates its first context with CreateOverSelectedRoot, then creates sibling contexts with CreateOverPhysicalDeviceOwner.

Typical headless usage:

auto maybeDevice = GeodeDevice::CreateHeadless();
if (!maybeDevice) {
  // No GPU available.
  return;
}

Class Documentation

◆ donner::geode::GeodeDevice::ReadbackStats

struct donner::geode::GeodeDevice::ReadbackStats

Readback timing, completion, loss, cancellation, and resource counters.

Class Members
uint64_t bindgroupCreates = 0
uint64_t bufferCreates = 0 GPU allocation and submission work performed by isolated captures.
uint64_t captureCancellations = 0 Captures cancelled while acquiring the context, mapping, or copying pixels.
uint64_t captureTimeouts = 0 Captures whose total deadline expired.
uint64_t contextCreates = 0 Lazily created readback-only contexts; independent of rendering pipelines.
int count = 0 Readback buffer-map waits run since the last consume, including waits that were cancelled or timed out.
bool deviceLost = false True once this device has been declared lost. Sticky, so every later consume keeps reporting it: a frame that never rendered has no other evidence to carry.
int pollIterations = 0 Bounded wait iterations those readbacks ran.
uint64_t poolBytes = 0
uint64_t poolEntries = 0 Idle pooled resource sets and their logical backing bytes after the latest capture.
uint64_t sharedTextureTailBytes = 0 Bytes of this context's textures still resident because another context registered them or an export of them is alive, after this context released its own handle. No context counts that memory as its allocation, so a working set has to add it.
uint64_t submits = 0
uint64_t textureCreates = 0
int timedOutWaitMs = 0 Wall time that wait spent before giving up, in milliseconds.
GpuWaitSite timedOutWaitSite = GpuWaitSite::None Bounded wait that declared that loss, or None.
bool usedTimedWaitAny = false True when any of those waits blocked on the map's completion event rather than only polling for it (gpu::MapWaitKind::CompletionEvent).

Member Function Documentation

◆ AllocateBufferId()

uint64_t donner::geode::GeodeDevice::AllocateBufferId ( )
staticnodiscard

Allocate a process-unique identity for a GPU buffer handle, from a monotonic counter that starts at 1 and is never reused.

Anything that outlives a buffer and still has to answer "is this the same buffer I saw before?" must compare these ids rather than backend handle addresses. The runtime may release a handle while submitted work still retains its allocation; a later allocation can reuse an address and make unrelated buffers appear identical. deviceId() exists for the same reason one level up.

0 is reserved for "no buffer", so a default-constructed id never matches a real one.

◆ beginFrameGeneration()

uint64_t donner::geode::GeodeDevice::beginFrameGeneration ( )
inline

Open a frame on this device and return its generation.

Generations are DEVICE-scoped and monotonic, so two renderers sharing one device cannot mint the same index. That happens routinely: an offscreen renderer built from this device renders an feImage fragment or a layer thumbnail from the same document while the outer renderer's frame is still open and has already recorded draws. With per-renderer counters the two frames alias, and a cache keyed on "was this touched in the current frame?" cannot tell the inner pass from the outer one - it would let the inner pass rewrite buffers the outer pass's recorded draws read, and every buffer write in a frame lands before every draw in that frame's submit.

Pair with endFrameGeneration. A cache that must not recycle memory an unsubmitted frame still reads compares against oldestOpenFrameGeneration() rather than against its own index.

◆ countCommandBuffers()

void donner::geode::GeodeDevice::countCommandBuffers ( uint64_t count) const
inline

Record the command buffers one submission carried.

Parameters
countCommand buffers handed to the queue together.

◆ countDraws()

void donner::geode::GeodeDevice::countDraws ( uint64_t count) const
inline

Record the draws a submission counted (see gpu::DeviceObserver::onSubmitted).

Parameters
countDraws counted.

◆ CreateHeadless()

std::unique_ptr< GeodeDevice > donner::geode::GeodeDevice::CreateHeadless ( gpu::TextureFormat textureFormat = gpu::TextureFormat::RGBA8Unorm)
static

Create a headless GeodeDevice.

Selects a GPU root with default options, so DONNER_GPU_BACKEND applies: a value that names no backend, or one this process cannot open, halts the process.

Parameters
textureFormatFormat the context's render targets and pipelines are built for.
Returns
A valid GeodeDevice on success, or an empty unique_ptr if the runtime could not create a GPU device (e.g., no GPU, no driver).

◆ CreateOverPhysicalDeviceOwner()

std::unique_ptr< GeodeDevice > donner::geode::GeodeDevice::CreateOverPhysicalDeviceOwner ( std::shared_ptr< GeodePhysicalDeviceOwner > physicalDevice,
gpu::TextureFormat textureFormat )
static

Creates another logical context over the selected physical owner.

It shares the backend root and loss condition with the first context while retaining its own runtime device, handle table, submission serials, counters, and pipelines. Native and browser roots use the same shared-owner path.

Parameters
physicalDeviceOwner retained by the first context; null or lost owners are refused.
textureFormatFormat this context's render targets and pipelines are built for.
Returns
A distinct logical context, or null when a usable device cannot be created.

◆ CreateOverSelectedRoot()

std::unique_ptr< GeodeDevice > donner::geode::GeodeDevice::CreateOverSelectedRoot ( std::shared_ptr< GeodeGpuRoot > root,
gpu::TextureFormat textureFormat )
static

Creates the first logical context over a backend root the caller already selected.

The editor and native embed example select against their actual window surface before opening a logical device. This context takes the selected root's first runtime device.

Parameters
rootSelected backend root; must not be null.
textureFormatFormat the context's render targets and pipelines are built for.
Returns
A valid context, or null when no runtime device could be opened over the root.
Examples
geode_embed.cc.

◆ deferDestroy()

void donner::geode::GeodeDevice::deferDestroy ( gpu::BindGroup bindGroup)

Enqueue a bind group for deferred destruction.

The handle is kept alive until drainDeferredDestroys() is called: a bind group evicted from a cache may still be named by draws that have been recorded but not yet replayed to the backend, and destroying it there fails those draws closed.

◆ deferDestroyTextureBacking()

bool donner::geode::GeodeDevice::deferDestroyTextureBacking ( gpu::Texture && texture)
nodiscard

Transfer owned texture backing to this context's thread-safe retirement mailbox.

Enqueuing checks only immutable device identity and never touches the resource table. The owning rendering context or exclusive teardown must drain the mailbox.

Parameters
textureHandle consumed on success; unchanged for a null or foreign handle.
Returns
Whether the handle was accepted.

◆ deferDestroyTextureBackingAfterSerial()

bool donner::geode::GeodeDevice::deferDestroyTextureBackingAfterSerial ( gpu::Texture && texture,
uint64_t serial )
nodiscard

Retain a failed frame's owned texture until this context has completed serial, then destroy its backing instead of recycling it with any unsubmitted writes.

Parameters
textureOwned texture handle; consumed on success.
serialLast submission that could have named the texture.
Returns
Whether this context accepted the handle.

◆ deviceId()

uint64_t donner::geode::GeodeDevice::deviceId ( ) const
inline

Process-unique identity for this device instance, assigned at construction from a monotonic counter (never reused, starts at 1).

Keys the GPU residence a document keeps per device (see GeodePerDevice), so each device that draws a document finds its own slabs and slots and never another's. Residence slots also record it, and the draw path treats a slot whose id does not match as non-resident, a defensive cross-check since GPU backends reject cross-device resources inside a render pass. A monotonic counter (rather than a raw this pointer) avoids the ABA hazard of a freed device's address being recycled by a later allocation.

◆ drainDeferredDestroys()

void donner::geode::GeodeDevice::drainDeferredDestroys ( )

Drop all deferred-destroy handles, releasing their GPU resources.

Called at the top of each frame (before new allocations) so resources from the previous frame's command buffer submission have had time to complete on the GPU. The runtime retires backing resources after submitted work completes.

◆ frameStampClaimed()

bool donner::geode::GeodeDevice::frameStampClaimed ( uint64_t stamp) const
inlinenodiscard

True when a resource stamped with stamp (a generation minted by beginFrameGeneration) may still be read by a frame that has not submitted: some open frame is at or before the stamp, so a recorded draw in that frame can reference the stamped bytes, and every queue write in a frame lands before every draw in its submit.

The never-drawn sentinel ~0 used by the resident-slot stamps is explicitly NOT claimed - a naive >= would read a never-drawn slot as claimed forever, since oldestOpenFrameGeneration() is also ~0 when no frame is open.

◆ handleRetirement()

const std::shared_ptr< GeodeHandleRetirement > & donner::geode::GeodeDevice::handleRetirement ( ) const
inline

Where state kept for this context on another thread's behalf - a document's resident slabs, say - hands back this context's buffers and bind groups when it is destroyed, so they are released on this context's thread (see GeodeHandleRetirement).

Shared so that state can tell whether this context still exists: it is closed when the context is destroyed.

◆ markDeviceLost()

void donner::geode::GeodeDevice::markDeviceLost ( const char * reason) const

Declare this device lost with no wait to attribute it to. Idempotent; the first call logs reason. Called when a frame's or a filter's commands cannot be closed, submitted, or restored, and available to embedders whose own device-lost signal is not shared through the selected root. Bounded waits that give up use markDeviceLostAfterWaitTimeout instead. Const because observers treat the flag as shared diagnostic state and waits that discover a hang run through const accessors.

Parameters
reasonHuman-readable cause, logged once.

◆ markDeviceLostAfterWaitTimeout()

void donner::geode::GeodeDevice::markDeviceLostAfterWaitTimeout ( GpuWaitSite site,
std::chrono::milliseconds elapsed,
const char * reason ) const

Declare this device lost because a bounded wait exceeded its deadline, recording which wait it was and how long it actually ran.

Prefer this over markDeviceLost at every deadline: the attribution is what turns "rendering stopped" into a diagnosable report, and it is only available at the wait site. Loss stays sticky, and only the call that declares it records an attribution; see DeclareDeviceLostAfterWaitTimeout for why that rule is what keeps a driver-reported loss from being relabelled as a wait timeout.

Parameters
siteWhich bounded wait expired.
elapsedWall time that wait spent before giving up.
reasonHuman-readable cause, logged once like markDeviceLost.

◆ recordReadback()

void donner::geode::GeodeDevice::recordReadback ( bool usedTimedWaitAny,
int pollIterations )

Record one readback buffer-map wait from a renderer sharing this device, whether or not the map completed.

Parameters
usedTimedWaitAnyWhether any iteration of the wait blocked on the map's completion event.
pollIterationsBounded wait iterations the readback ran.

◆ runtimeCounterObserverForTesting()

gpu::DeviceObserver & donner::geode::GeodeDevice::runtimeCounterObserverForTesting ( ) const

The observer this context installs on its own runtime device, on every backend.

It reports what that device allocates, uploads, and submits through the count* members above, so the counters follow the same rules whichever backend renders. Texture upload bytes are what each backend hands its queue, so they can differ where a backend repacks rows.

A test that installs it on another runtime device attributes that device's work to this context as well, and removes it again before either is destroyed.

◆ setCounters()

void donner::geode::GeodeDevice::setCounters ( GeodeCounters * counters)
inline

Install a GeodeCounters struct for this device.

Non-owning; the caller must keep the struct alive for as long as the device might increment it. Pass nullptr to disable instrumentation.

All Geode components that hold a GeodeDevice& route their per-frame hot-path allocation and submission sites through this hook.

◆ setSnapshotReadbackBudgetForTesting()

void donner::geode::GeodeDevice::setSnapshotReadbackBudgetForTesting ( std::chrono::milliseconds budget)
inline

Override the total capture budget for deterministic cancellation/deadline tests.

Parameters
budgetIncludes context acquisition and GPU mapping.

◆ setSnapshotReadbackHookForTesting()

void donner::geode::GeodeDevice::setSnapshotReadbackHookForTesting ( std::function< void(SnapshotReadbackPhase)> hook)

Install a capture-phase test hook; it may be called concurrently by capture waiters.

Parameters
hookHook to install; empty removes it. Set only while captures are quiescent.

◆ waitForQueueIdle()

GpuWaitResult donner::geode::GeodeDevice::waitForQueueIdle ( std::chrono::milliseconds stallBound = kDefaultGpuWaitTimeout) const

Wait, bounded by lack of progress, for all submitted GPU work to complete.

Waits through this context's runtime device for its last submitted serial, rather than asking whether a queue shared with other contexts is momentarily empty. That serial completes only after everything queued ahead of it, so the wait gives up only when that work stops making progress for stallBound (see gpu::Device::waitForSerialUnlessStalled), never because a slow device's backlog is long. A stall declares the device lost, attributed to the queue-idle wait with the time the wait actually spent, and later waits return immediately. A runtime device that declares that loss itself reports it as DeviceLost rather than TimedOut.

Parameters
stallBoundLongest the work may go without progress; defaults to the shared bound.
Returns
Complete when the queue drained, TimedOut when the work stopped progressing or the backend failed before the queue went idle (the device is now marked lost either way), or DeviceLost when the device was already lost and no wait was performed, or a loss was declared while the wait was running.

◆ waitForSnapshotCaptureIdleForTesting()

GpuWaitResult donner::geode::GeodeDevice::waitForSnapshotCaptureIdleForTesting ( std::chrono::milliseconds timeout = kDefaultGpuWaitTimeout)
nodiscard

Waits until the snapshot capture context's queue has no submitted work left, so a test can check what the owner's next release point frees once every capture has finished on the GPU, without polling for it.

Waits for a capture in progress to end first.

Parameters
timeoutBound on the queue wait; a timeout is declared like any queue-idle wait.
Returns
GpuWaitResult::Complete when the queue is idle or no capture context exists.

The documentation for this class was generated from the following file: