Donner SVG 0.8.0-pre
SVG editor and embeddable C⁠+⁠+⁠20 engine.
Loading...
Searching...
No Matches
donner::editor::AsyncRenderer Class Reference

Classes

struct  GpuWaitFailure
 Device-health outcome the render worker observed, independent of any frame it produced. More...

Public Member Functions

 AsyncRenderer (AsyncRendererStartMode startMode=AsyncRendererStartMode::Immediate)
 AsyncRenderer (const AsyncRenderer &)=delete
AsyncRenderer & operator= (const AsyncRenderer &)=delete
 AsyncRenderer (AsyncRenderer &&)=delete
AsyncRenderer & operator= (AsyncRenderer &&)=delete
void start ()
 Start the render worker after its borrowed main-thread dependencies are ready.
bool workerStartedForTesting () const
 True when this instance currently owns a joinable/running render worker.
void shutdown ()
 Stop accepting work, cancel both priority lanes, detach the wake callback, and join the worker.
bool isBusy () const
 Returns true while a render/result or document-reading cache warmup owns the input gate. The UI thread must not touch the Renderer or mutate the SVGDocument while this returns true.
bool hasRenderInFlightForTesting () const
 Returns true only while the worker may still be computing or cancelling a render. Unlike isBusy(), a staged result waiting in DoneState is not in flight.
bool hasPendingRenderForTesting () const
 Whether a render request is still queued rather than owned by the worker.
bool waitUntilNoRenderInFlightForTesting (std::chrono::steady_clock::time_point deadline)
 Wait until no worker render is actively in flight.
bool compositorUsesRetainedDocumentForTesting () const
 Whether the compositor's document reference is bound to the renderer-owned retained value. A compositor bound to a request-local RenderLease becomes dangling before deferred warmup.
void setReplayRenderDelayForTesting (std::chrono::milliseconds delay)
 Inject a fixed delay into each worker render attempt for replay tests.
void setReplayResultHoldFramesForTesting (int frameCount)
 Hold each staged result for a fixed number of poll attempts in replay tests.
void stageCompositorWarmupForTesting (bool pending, bool active)
 Install a synthetic low-priority warmup state for document-access gate tests.
void completeCompositorWarmupForTesting ()
 Simulate the active warmup releasing its document guard.
std::uint64_t replayResultHoldPollCountForTesting () const
 Number of poll attempts that intentionally withheld a staged result for replay tests.
void requestRender (const RenderRequest &request)
 Post a render request to the worker. Non-blocking. If the worker is busy, this cancels the in-flight render at the next compositor safe point and replaces the pending request slot with the latest request.
void cancelInFlight ()
 Cancel an in-flight render without posting a replacement. Use when the current render is dispensable and the UI needs the worker to become idle before dispatching registry-touching input. Safe to call from any thread.
std::uint64_t cancelledRenderCount () const
 Count of renders that were cancelled mid-flight by a subsequent requestRender. Exposed for tests to assert preemption is engaging (vs. the worker silently queueing requests). Incremented under the internal mutex; safe to read from any thread.
std::optional< RenderResultpollResult ()
 If a render has completed since the last call, returns the resulting bitmap and transitions the worker back to idle. Returns std::nullopt if no render is pending-ready (either still busy or idle with nothing to hand off).
bool requestSampleThumbnail (SampleThumbnailRenderRequest request)
 Queue one low-priority SVG thumbnail on this renderer's existing worker.
std::optional< SampleThumbnailRenderResultpollSampleThumbnailResult ()
 Poll one completed sample-thumbnail result without changing main-document busy state.
void cancelSampleThumbnailWork ()
 Drop queued/unpolled sample-thumbnail work and cancel an active attempt.
SampleThumbnailRenderStats sampleThumbnailRenderStats () const
 Snapshot low-priority worker counters and slot state.
void setSampleThumbnailRenderDelayForTesting (std::chrono::milliseconds delay)
 Inject a cancellation-aware delay before thumbnail parsing for deterministic priority tests.
void setSampleThumbnailRendererCreationPlanForTesting (int requestNumber, std::chrono::milliseconds delay)
 Recreate and pause one numbered offscreen renderer construction for browser handoff tests.
void setWakeCallback (std::function< void()> callback)
 Install a callback that the worker thread invokes when a render result or cancellation completes. Used by the editor's on-demand render loop to wake the UI thread (e.g. via glfwPostEmptyEvent) so fresh results or newly-idle deferred input get picked up without continuous polling.
void setTightBoundedSegmentsEnabled (bool enabled)
 Toggle whether the compositor uses tight-bounded segment rasterization. The change applies at the start of the next worker iteration - renderFrame calls CompositorController::setTightBoundedSegmentsEnabled before compositing, which marks all cached segments dirty so the flip takes full effect that frame.
bool tightBoundedSegmentsEnabled () const
 Mirror of the current toggle state. UI reads this to render the correct check state in the View menu without racing the worker.
void setCompositedRenderingMode (CompositedRenderingMode mode)
 Select how the worker uses the compositor: full compositing, cached layers for filters only, or no compositor at all (direct full-document renders). See CompositedRenderingMode. The change applies at the start of the next worker iteration: entering Off destroys the live CompositorController; leaving Off or changing between the other modes reconstructs it with the matching CompositorConfig. Every mode produces identical pixels.
CompositedRenderingMode compositedRenderingMode () const
 Mirror of the current mode. UI reads this to render the correct radio state in the View menu without racing the worker.
void setGeometryDebugOverlayEnabled (bool enabled)
 Toggle the Geode geometry debug overlay (RendererInterface::setDebugGeometryOverlay) on the root document renderer. The change applies at the start of the next worker iteration. Each state transition clears retained compositor state once. While enabled, selection promotion/prewarm remains suppressed and every render presents one flat full-document root frame so retained tiles cannot crop or cover the frame-final wireframe. Disabling performs one transition reset, then normal retained promotion resumes.
bool geometryDebugOverlayEnabled () const
 Mirror of the current overlay state. UI reads this to render the correct check state in the View menu without racing the worker.
std::uint64_t compositorResetCountForTesting () const
 Number of times the worker has called CompositorController::resetAllLayers() since construction. Tests use this to assert that frame-version mutations do not masquerade as document replacements.
std::uint64_t compositorReconstructCountForTesting () const
 Number of times the worker has reconstructed compositor_ from scratch. First construction counts as one. Tests use this to verify that structural remaps preserve cached layer state across drag-writeback reparses.
svg::compositor::CompositorController::FastPathCounters compositorFastPathCountersForTesting () const
 Snapshot of the compositor's fast-path counters. Read-only - the worker writes them under the mutex when transitioning to Done. Returns zeros before the compositor is constructed (first render not yet requested). UI-thread safe.
svg::compositor::CompositorController::RenderFrameStats compositorRenderFrameStats () const
 Snapshot of the worker compositor's immediate-vs-cached raster costs from the latest completed render.
GpuWaitFailure gpuWaitFailure () const
 Snapshot of the worker's GPU-wait failure record. UI-thread safe.
void noteGpuWaitOutcomeForTesting (const svg::RendererReadbackStats &readbackStats)
 Fold one render attempt's device-health stats into the failure record, as the worker does at the end of every iteration. Tests use this to pin the record's deduplication without hanging a real GPU.
std::vector< svg::compositor::CompositorController::LayerInspectorRowcompositorLayerInspectorRows () const
 Snapshot of the compositor's per-layer diagnostic rows. Captured under the worker mutex at every Done transition; the UI thread copies the cached vector out under the lock. Empty before the first render lands or when the compositor isn't instantiated.
std::vector< svg::compositor::CompositorController::SegmentInspectorRowcompositorSegmentInspectorRows () const
 Snapshot of the compositor's per-segment diagnostic rows. Same capture point and locking as the per-layer rows.
std::vector< svg::compositor::CompositorController::CompositeTileSnapshotcompositorCompositeTiles () const
 Unified in-paint-order snapshot of every tile the compositor samples to produce the final composite. The editor's layer-inspector panel renders this list with thumbnails for every tile so the operator can see the comprehensive composite at a glance.
svg::compositor::CompositorController::StateSnapshot compositorState () const
 Compositor-wide diagnostic state: active-hints count, layer count, split-path active flag, drag-target entity, canvas size. The editor's layer-inspector panel renders this as a state header so the operator can spot mismatches between the editor's idea of the drag target and the compositor's.
Entity workerCompositorEntity () const
 The worker's current view of which entity is promoted. Read on the UI thread; the worker updates it under the same mutex as the other snapshot fields when transitioning to Done. entt::null when the worker hasn't promoted anything (e.g. promotion was refused). Compare against the editor's selection to spot races between the editor's selectedEntity and what the compositor actually holds.
Vector2i lastDocumentCanvasSize () const
 Output raster size from the worker's last-completed render. This is the presentation epoch: at high zoom it can be smaller than the SVG document's semantic canvas size because the worker rendered only the visible viewport plus margin.
void setCompositorDiagnosticsEnabled (bool enabled)
 Enable expensive compositor inspector snapshots for the developer panel. Scalar render timing and fast-path counters remain available when disabled.

Class Documentation

◆ donner::editor::AsyncRenderer::GpuWaitFailure

struct donner::editor::AsyncRenderer::GpuWaitFailure

Device-health outcome the render worker observed, independent of any frame it produced.

A bounded GPU wait that burns its deadline declares the device lost and ends the worker iteration with nothing to hand over, so the per-frame diagnostics a result carries are never published. That makes the most severe renderer failure the only one that leaves no trace in the frame stats. The worker records the outcome here instead, so a poller can report it without a frame ever landing.

Class Members
bool deviceLost = false True once the worker's backend device has been declared lost. Sticky.
uint64_t generation = 0 Bumped whenever the record above changes. A poller compares it against what it last reported so a sticky loss is reported once rather than on every frame.
int timedOutWaitMs = 0 Wall time that wait spent before giving up, in milliseconds.
GpuWaitTimeoutSite timedOutWaitSite = svg::GpuWaitTimeoutSite::None Which bounded GPU wait declared that loss, when a deadline did.

Member Function Documentation

◆ compositorReconstructCountForTesting()

std::uint64_t donner::editor::AsyncRenderer::compositorReconstructCountForTesting ( ) const
inlinenodiscard

Number of times the worker has reconstructed compositor_ from scratch. First construction counts as one. Tests use this to verify that structural remaps preserve cached layer state across drag-writeback reparses.

Safe to read from the UI thread; incremented under the internal mutex on the worker.

◆ compositorResetCountForTesting()

std::uint64_t donner::editor::AsyncRenderer::compositorResetCountForTesting ( ) const
inlinenodiscard

Number of times the worker has called CompositorController::resetAllLayers() since construction. Tests use this to assert that frame-version mutations do not masquerade as document replacements.

Counts resets driven by a request.documentGeneration mismatch and geometry-debug state transitions; not the implicit reset performed on first compositor construction.

Safe to read from the UI thread; incremented under the internal mutex on the worker.

◆ requestSampleThumbnail()

bool donner::editor::AsyncRenderer::requestSampleThumbnail ( SampleThumbnailRenderRequest request)
nodiscard

Queue one low-priority SVG thumbnail on this renderer's existing worker.

The lane has exactly one slot spanning pending, active, and completed-but-unpolled work. Main document renders always take priority and cancel an active thumbnail at the next safe point.

Returns
True when the request was accepted, false when the bounded slot is occupied or the renderer is shutting down.

◆ setCompositedRenderingMode()

void donner::editor::AsyncRenderer::setCompositedRenderingMode ( CompositedRenderingMode mode)
inline

Select how the worker uses the compositor: full compositing, cached layers for filters only, or no compositor at all (direct full-document renders). See CompositedRenderingMode. The change applies at the start of the next worker iteration: entering Off destroys the live CompositorController; leaving Off or changing between the other modes reconstructs it with the matching CompositorConfig. Every mode produces identical pixels.

Same threading contract as setTightBoundedSegmentsEnabled: safe to call from the UI thread while a render is in flight.

◆ setGeometryDebugOverlayEnabled()

void donner::editor::AsyncRenderer::setGeometryDebugOverlayEnabled ( bool enabled)
inline

Toggle the Geode geometry debug overlay (RendererInterface::setDebugGeometryOverlay) on the root document renderer. The change applies at the start of the next worker iteration. Each state transition clears retained compositor state once. While enabled, selection promotion/prewarm remains suppressed and every render presents one flat full-document root frame so retained tiles cannot crop or cover the frame-final wireframe. Disabling performs one transition reset, then normal retained promotion resumes.

Same threading contract as setTightBoundedSegmentsEnabled: safe to call from the UI thread while a render is in flight.

◆ setReplayRenderDelayForTesting()

void donner::editor::AsyncRenderer::setReplayRenderDelayForTesting ( std::chrono::milliseconds delay)

Inject a fixed delay into each worker render attempt for replay tests.

Parameters
delayDelay duration. Negative durations are clamped to zero.

◆ setReplayResultHoldFramesForTesting()

void donner::editor::AsyncRenderer::setReplayResultHoldFramesForTesting ( int frameCount)

Hold each staged result for a fixed number of poll attempts in replay tests.

Parameters
frameCountNumber of poll attempts to withhold a newly staged result.

◆ setTightBoundedSegmentsEnabled()

void donner::editor::AsyncRenderer::setTightBoundedSegmentsEnabled ( bool enabled)
inline

Toggle whether the compositor uses tight-bounded segment rasterization. The change applies at the start of the next worker iteration - renderFrame calls CompositorController::setTightBoundedSegmentsEnabled before compositing, which marks all cached segments dirty so the flip takes full effect that frame.

Safe to call from the UI thread while a render is in flight; the flag is stored in an std::atomic<bool>, and the worker reads it at a well-defined point in each iteration.

◆ setWakeCallback()

void donner::editor::AsyncRenderer::setWakeCallback ( std::function< void()> callback)

Install a callback that the worker thread invokes when a render result or cancellation completes. Used by the editor's on-demand render loop to wake the UI thread (e.g. via glfwPostEmptyEvent) so fresh results or newly-idle deferred input get picked up without continuous polling.

The callback runs on the worker thread. It must be thread-safe and must NOT re-enter the renderer - a simple wake-up post into the window's event queue is the intended use.

◆ shutdown()

void donner::editor::AsyncRenderer::shutdown ( )

Stop accepting work, cancel both priority lanes, detach the wake callback, and join the worker.

Safe to call more than once from the owning thread. The destructor calls this automatically; owners with borrowed worker dependencies may call it earlier to control teardown order.

◆ start()

void donner::editor::AsyncRenderer::start ( )

Start the render worker after its borrowed main-thread dependencies are ready.

Native construction starts immediately for existing standalone users. Browser editor startup calls this explicitly after synchronous main-thread WebGPU initialization, because Safari cannot safely interleave another device's Promise completion with an Asyncify readback. Repeated calls and calls after shutdown are no-ops.

◆ waitUntilNoRenderInFlightForTesting()

bool donner::editor::AsyncRenderer::waitUntilNoRenderInFlightForTesting ( std::chrono::steady_clock::time_point deadline)
nodiscard

Wait until no worker render is actively in flight.

Parameters
deadlineSteady-clock deadline for the bounded wait.

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