|
|
Donner SVG 0.8.0-pre
SVG editor and embeddable C++20 engine.
|
AsyncRenderer owns a svg::Renderer and runs compositor rendering plus any final presentation snapshot handoff on a dedicated worker thread so heavy renders don't block the UI thread. More...
#include <algorithm>#include <atomic>#include <chrono>#include <condition_variable>#include <cstdint>#include <functional>#include <memory>#include <mutex>#include <optional>#include <string>#include <thread>#include <unordered_map>#include <variant>#include <vector>#include "donner/base/EcsRegistry.h"#include "donner/base/Transform.h"#include "donner/base/Vector2.h"#include "donner/editor/CompositedRenderingMode.h"#include "donner/editor/OverlayRenderer.h"#include "donner/editor/ViewportState.h"#include "donner/svg/SVGDocument.h"#include "donner/svg/SVGElement.h"#include "donner/svg/compositor/CompositorController.h"#include "donner/svg/compositor/ScopedCompositorHint.h"#include "donner/svg/renderer/Renderer.h"#include "donner/svg/renderer/RendererInterface.h"Classes | |
| struct | donner::editor::RenderLease |
| Non-null renderer/document handoff for a render request. More... | |
| struct | donner::editor::RenderRequest |
| Per-request handoff data captured at render-request time so the worker has everything it needs without touching live UI state. More... | |
| struct | donner::editor::RenderRequest::DragPreview |
| struct | donner::editor::PresentationSnapshotPlan |
| Final full-canvas snapshot work needed after compositor rendering. More... | |
| struct | donner::editor::HandoffTimings |
| Attribution of one worker-to-UI handoff, in milliseconds. More... | |
| struct | donner::editor::RenderResult |
| Presentation payload plus the document version it was rendered from. More... | |
| struct | donner::editor::RenderResult::WorkerTimingBreakdown |
| Internal timing split for one async worker iteration. More... | |
| struct | donner::editor::RenderResult::CompositedTile |
| One composite tile from the worker's CompositorController::
snapshotCompositorTiles() snapshot. The editor uploads one GL texture per tile (keyed on id). The GL presenter composes those cached textures into one pane-sized presentation texture; the WebGPU presenter composites them directly into the framebuffer. Immediate tiles intentionally use transient ids and always carry a fresh payload. Geometry fields are doc-unit quantities so the editor can scale them by the current pixelsPerDocUnit during canvas-resize debouncing. More... | |
| struct | donner::editor::RenderResult::CompositedPreview |
| struct | donner::editor::SampleThumbnailRenderRequest |
| One SVG source queued for bounded, low-priority rendering on the existing render worker. More... | |
| struct | donner::editor::SampleThumbnailRenderResult |
| CPU bitmap returned by one asynchronous sample-thumbnail attempt. More... | |
| struct | donner::editor::SampleThumbnailRenderStats |
| Observable state and monotonic counters for the bounded sample-thumbnail lane. More... | |
| class | donner::editor::AsyncRenderer |
| struct | donner::editor::AsyncRenderer::GpuWaitFailure |
| Device-health outcome the render worker observed, independent of any frame it produced. More... | |
Namespaces | |
| namespace | donner |
| Top-level Donner namespace, which is split into different sub-namespaces such as donner::svg and donner::css. | |
| namespace | donner::svg |
| Donner SVG library, which can load, manipulate and render SVG files. | |
Enumerations | |
| enum class | donner::editor::SampleThumbnailRenderOutcome : std::uint8_t { Rendered , Cancelled , ParseError , RenderError , RendererUnavailable } |
| Terminal outcome for one low-priority sample-thumbnail render attempt. | |
| enum class | donner::editor::AuxiliaryPreviewKind : std::uint8_t { Sample , FontFamily } |
| Consumer of one bounded low-priority SVG preview render. | |
| enum class | donner::editor::AsyncRendererStartMode : std::uint8_t { Immediate , Deferred } |
| Whether construction starts the render worker or leaves it inert until an explicit start call. | |
Functions | |
| PresentationSnapshotPlan | donner::editor::ChoosePresentationSnapshotPlan (bool hasCompositedPreview, bool requiresTextureSnapshotPresentation, bool captureCpuSnapshot) |
| Choose final full-canvas snapshot work for a render result. | |
| HandoffTimings | donner::editor::ComputeHandoffTimings (std::chrono::steady_clock::time_point workerCompletedAt, std::chrono::steady_clock::time_point polledAt) |
| Attribute the worker-to-UI handoff delay. | |
AsyncRenderer owns a svg::Renderer and runs compositor rendering plus any final presentation snapshot handoff on a dedicated worker thread so heavy renders don't block the UI thread.
The worker thread owns the Renderer for its entire lifetime. Backends with thread-affined GPU objects depend on device, pipeline, texture, and readback use staying on that thread.
The worker additionally takes exclusive ownership of the SVGDocument during an active render. The UI thread must not mutate the document while a render is in flight.
UI thread flow per frame:
The safety invariant: between requestRender() and a non-nullopt return from pollResult(), the UI thread must not mutate the SVGDocument. Registry-reading UI paths should normally gate on !isBusy() unless they are using guarded access for immediate overlay presentation. The UI thread must not call any method on the worker Renderer at any time - it lives on the worker.
| struct donner::editor::RenderRequest::DragPreview |
| Class Members | ||
|---|---|---|
| Transform2d | documentFromCachedDocument = Transform2d() | Active affine transform represented by this request, relative to the drag-start cached document. Selection prewarms use identity. |
| uint64_t | dragGeneration = 0 | Monotonic id for the active drag gesture. Selection prewarms use zero. |
| Entity | entity = entt::null | |
| vector< Entity > | extraEntities | Additional entities moving with entity under the same active drag transform. |
| bool | forceLayerRasterization = false | True when this request must re-rasterize the promoted drag layer instead of only publishing updated compose metadata. Used for scheduler-requested affine recaptures that keep scaled drag previews crisp. |
| InteractionHint | interactionKind = svg::compositor::InteractionHint::ActiveDrag | Which interaction phase drove this preview. Selection means the editor is pre-warming a layer for the selected entity before any drag begins. ActiveDrag means the user is actively dragging - the DOM's transform attribute already reflects the cursor delta. The compositor stamps the correct InteractionHint on the entity based on this field so downstream introspection stays accurate. |
| Vector2d | translation = Vector2d::Zero() | Active drag translation represented by this request. Selection prewarms use zero. |
| struct donner::editor::RenderResult::WorkerTimingBreakdown |
Internal timing split for one async worker iteration.
| Class Members | ||
|---|---|---|
| double | buildPreviewMs = 0.0 | Time spent building composited-preview tile metadata/payloads. |
| double | dequeueToStartMs = 0.0 | Worker-thread preflight between dequeue and the measured render iteration. |
| bool | deviceLost = false | True when the worker's backend device has been declared lost, either by the driver or by a bounded GPU wait exceeding its deadline. |
| double | diagnosticsMs = 0.0 | Time spent copying compositor diagnostics for editor panels. |
| double | finalSnapshotMs = 0.0 | Time spent taking the final fallback canvas snapshot, when needed. |
| double | pollDelayMs = 0.0 | Time from worker result completion until the UI thread polls it. |
| double | queueWaitMs = 0.0 | Time from UI-thread request submission until the worker dequeues the request. |
| int | readbackCount = 0 | GPU-to-CPU readbacks performed by the worker renderer and its offscreen instances. |
| int | readbackPollIterations = 0 | Legacy device-poll iterations used while waiting for those readbacks. |
| double | renderFrameMs = 0.0 | Time spent in CompositorController::renderFrame. |
| double | setupMs = 0.0 | Time before CompositorController::renderFrame, including compositor selection setup. |
| 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. |
| bool | usedTimedWaitAny = false | True when browser readbacks used the event-driven timed WaitAny path. |
| double | wakeToPollMs = 0.0 | Portion of pollDelayMs spent waiting for the UI thread's next frame after the result became pollable. This is the handoff's animation-frame phase wait. |
| 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. |
|
nodiscard |
Choose final full-canvas snapshot work for a render result.
| hasCompositedPreview | True when compositor tiles already provide the presented pixels. |
| requiresTextureSnapshotPresentation | True when presentation must remain on GPU textures. |
| captureCpuSnapshot | True when the caller explicitly requested a CPU-readable frame. |
|
inline |
Attribute the worker-to-UI handoff delay.
A default-constructed workerCompletedAt means "not recorded" and yields all-zero timings. Timestamps that go backwards are clamped to zero rather than reported as negative durations.
| workerCompletedAt | When the worker finished the render and staged the result. |
| polledAt | When the UI thread accepted the result. |