Donner 0.8.0-pre
Embeddable browser-grade SVG2 engine
Loading...
Searching...
No Matches
donner::svg::compositor::CompositorController Class Reference

Controls compositor layer promotion/demotion and orchestrates composited rendering. More...

#include "donner/svg/compositor/CompositorController.h"

Classes

struct  PromoteResult
 Result of requesting an editor-facing compositor presentation plan. More...
struct  FastPathCounters
 Diagnostic counters for the translation-only fast path. Tests read these to assert that a drag is taking the fast path every frame, not falling through to prepareDocumentForRendering. More...
struct  LayerInspectorRow
 One row of diagnostic state per active compositor layer, intended for the editor's read-only layer-inspector panel (design doc 0033 M1). Cheap to build, cheap to copy: a few ints and one short string per layer. More...
struct  SegmentInspectorRow
 One row of diagnostic state per static segment (the non-promoted content between promoted layers, plus the pre-first and post-last slots). Sized N+1 where N is layerCount(). More...
struct  StaticSpanPlan
 Conservative draw-cost plan for one static segment slot. More...
struct  CompositeTileSnapshot
 One row of the unified "everything composited together" view that the layer-inspector panel renders in paint order — design doc 0033 §M1++. Mirrors what composeLayers actually draws so the operator sees the same sequence of blits the renderer performs. More...
struct  RenderFrameStats
 Worker render costs from the most recent renderFrame call, split by whether the work was caused by immediate-mode transient spans or retained cached tiles. More...
struct  StateSnapshot

Public Types

enum class  SnapshotThumbnails : uint8_t {
  Include ,
  Omit
}
 Whether diagnostic snapshots should synthesize CPU thumbnails.
enum class  PromoteRefusalReason : uint8_t {
  None = 0 ,
  InvalidEntity ,
  LayerLimit ,
  MemoryLimit ,
  DescendantPromoted
}
 Compositor-wide state useful for diagnosing why the editor's expected drag fast path didn't engage. Lets the operator confirm at a glance: More...

Public Member Functions

 CompositorController (SVGDocument &document, RendererInterface &renderer, CompositorConfig config={})
 Construct a compositor controller.
const CompositorConfigconfig () const
 Returns the runtime config this controller was constructed with.
 ~CompositorController ()
 Destructor.
 CompositorController (const CompositorController &)=delete
CompositorControlleroperator= (const CompositorController &)=delete
 CompositorController (CompositorController &&) noexcept
CompositorControlleroperator= (CompositorController &&) noexcept
PromoteResult promoteEntity (Entity entity, InteractionHint interactionKind=InteractionHint::ActiveDrag)
 Promote an entity to its own compositor layer.
void demoteEntity (Entity entity)
 Demote a previously promoted entity back to the root layer.
bool isPromoted (Entity entity) const
 Returns true if the given entity is currently promoted to its own layer.
Transform2d layerComposeOffset (Entity entity) const
 Returns the current bitmap-compose offset for a promoted entity's layer, or identity if the entity is not promoted or has no cached bitmap.
void renderFrame (const RenderViewport &viewport)
 Prepare and render a composited frame.
void renderFrame (const RenderViewport &viewport, const Transform2d &surfaceFromCanvas)
 Prepare and render a composited frame into viewport after applying surfaceFromCanvas to canvas-space content.
bool renderFrame (const RenderViewport &viewport, CancellationToken &token)
 Design doc 0033 §M4 — cancellable variant. The token is polled at coarse safe points (between rasterizeLayer / segment rasterize calls) and renderFrame returns early when set. The compositor's internal dirty flags are left intact for the work the early return skipped, so the next renderFrame picks up without re-doing already-rasterized layers / segments.
bool renderFrame (const RenderViewport &viewport, CancellationToken &token, const Transform2d &surfaceFromCanvas)
 Cancellable variant of the camera-transform render path.
size_t layerCount () const
 Returns the number of currently active layers (excluding the root layer).
size_t totalBitmapMemory () const
 Returns the total memory used by all layer bitmaps, in bytes.
SVGDocumentdocument () const
 Returns a reference to the underlying SVG document.
FallbackReason fallbackReasonsOf (Entity entity) const
 Returns the fallback reasons for a promoted entity, or FallbackReason::None if not promoted.
bool hasSplitStaticLayers () const
 Returns true when the compositor has cached a split underlay/overlay pair for drag preview.
const RendererBitmaplayerBitmapOf (Entity entity) const
 Cached bitmap for the promoted entity, or an empty bitmap if unavailable.
Vector2d layerCanvasOffsetOf (Entity entity) const
 Canvas-space top-left of the entity's cached layer bitmap. Zero() when the entity is not promoted, when its layer hasn't rasterized yet, or when the layer fell back to canvas-size rasterization (design doc 0033 §M2). The editor's CompositedPreview consumer blits the promoted texture at this offset (converted to doc units) plus the per-frame DOM drag delta.
const FastPathCountersfastPathCountersForTesting () const
std::vector< LayerInspectorRowsnapshotLayerInspectorRows (SnapshotThumbnails thumbnails=SnapshotThumbnails::Include) const
 Build a per-layer snapshot of compositor state for the layer- inspector panel. Safe to call from the renderer worker thread when the compositor isn't mid-render (the editor calls it at the same Done-transition point as fastPathCountersForTesting). Allocates a vector and one short string per layer — fine for diagnostics, not hot-path-grade.
std::vector< SegmentInspectorRowsnapshotSegmentInspectorRows () const
 Snapshot per-segment diagnostic state. Mirrors the per-layer snapshot but covers the static-segment cache, which dominates the per-frame rasterize cost on documents like the splash. Same invocation rules as snapshotLayerInspectorRows.
std::vector< StaticSpanPlansnapshotStaticSpanPlansForTesting () const
 Snapshot the most recent static span plans. Test-only diagnostics.
std::vector< CompositeTileSnapshotsnapshotCompositeTiles (SnapshotThumbnails thumbnails=SnapshotThumbnails::Include) const
 Build the unified composite-tile snapshot in paint order. The sequence mirrors composeLayers:
const RenderFrameStatslastRenderFrameStats () const
 Return the current render-frame raster cost split.
StateSnapshot snapshotState () const
void resetAllLayers (bool documentReplaced=false)
 Clear all layers and cached state.
bool remapAfterStructuralReplace (const std::unordered_map< Entity, Entity > &remap)
 Rewire the compositor's entity-keyed state (activeHints_, mandatoryDetector_, complexityBucketer_, layers_) from the old document's entity space onto a new one, after a structurally identical setDocument.
void setTightBoundedSegmentsEnabled (bool enabled)
 Flip tight-bounded segment rasterization on or off at runtime. See CompositorConfig::tightBoundedSegments for semantics. Marks every cached static segment dirty so the next renderFrame call re-rasterizes under the new policy (otherwise the flip would affect only segments that happened to get re-rasterized for other reasons).
bool tightBoundedSegmentsEnabled () const
 Returns the current tight-bounded-segments setting. Mirrors config().tightBoundedSegments for convenience.
void setSkipMainComposeDuringSplit (bool skip)
 When true, renderFrame() skips the main-renderer compose step while the split-static-layers cache (bg/drag/fg triple) is populated. The editor's drag overlay reads those bitmaps directly via GL, so the per-frame drawImage calls into the main renderer are wasted work — on a 892×512 Skia backend with a few filter layers the skip saves ~100 ms per drag frame. The flat snapshot the editor uploads stays stale during drag but is only drawn after drag ends, by which point the caller must disable the skip for a settle render that refreshes it.
std::vector< CompositorTilesnapshotTilesForUpload (CompositorTileBitmapPayload payload=CompositorTileBitmapPayload::All) const
 Enumerate every cacheable unit (static segments + promoted layer bitmaps) interleaved in paint order. Each tile carries a generation counter that advances only when the tile's pixel content was actually re-rasterized — so the editor can gate its GL texture uploads to the minimum set that actually changed this frame. On a click-to-drag, the user should observe at most 3 tiles advance: the two halves of the split segment and the new drag-target layer. All other filter layers, segments, and bucket layers keep their generation and their GL texture binding.
const CompositorLayerfindLayerForTest (Entity entity) const
 Read-only accessor for the layer bound to entity. Test-only — lets regression tests inspect canvasFromBitmap / bitmapEntityFromWorldTransform after a drag frame to verify the translation-only fast path engaged (bitmap stamp unchanged, composition transform carries the delta). Production callers should go through isPromoted / promoteEntity instead.
void flushPendingDemotionsForTesting ()
 Test-only: bypass the §M9 hysteresis window and process every pending demotion immediately. Provided so unit tests can keep using the "promote → demote → assert layer gone" pattern without having to render kDemotionHysteresisFrames frames in the middle. Production code calls happen via the normal renderFrame flow, which ages the queue one frame at a time.

Static Public Attributes

static constexpr int kLayerThumbnailMaxSide = 64
 Max side length (in pixels) of the thumbnail bitmap synthesized into each LayerInspectorRow::thumbnailPixels. The downsample preserves aspect ratio, so the smaller side is round(otherSide * shortSide / longSide). 64 px keeps the memory cost trivial (16 KiB / layer max) while staying legible at the editor's right-pane width.
static constexpr uint32_t kDemotionHysteresisFrames = 30
 Frames the demotion waits before actually firing. ~0.5s at 60Hz — long enough to absorb the typical "click-deselect-click" rhythm (a few hundred ms), short enough that an actual commit-to-demote stays inside one human reaction time. Public so tests can drive renderFrame exactly the right number of times to observe the expiry transition.

Detailed Description

Controls compositor layer promotion/demotion and orchestrates composited rendering.

The compositor splits the document into layers: one root layer (everything not promoted) and zero or more promoted layers (one per promoted entity subtree). The DOM is the sole source of truth for entity position: during a drag, callers mutate the entity's transform directly (element.setTransform(...)) and the compositor's fast path diffs the new absolute transform against the cached bitmap's rasterize-time transform. When the delta is a pure translation, the bitmap is reused and only the internal compose offset updates — no re-rasterization.

Usage:

CompositorController compositor(document, renderer);
// Promote drag target
compositor.promoteEntity(dragTarget);
// During drag — mutate the DOM; the compositor tracks the delta internally.
dragElement.setTransform(Transform2d::Translate(dx, dy));
compositor.renderFrame(viewport);
// When drag ends
compositor.demoteEntity(dragTarget);
SVGDocument & document() const
Returns a reference to the underlying SVG document.
Definition CompositorController.h:422
CompositorController(SVGDocument &document, RendererInterface &renderer, CompositorConfig config={})
Construct a compositor controller.
static Transform2 Translate(const Vector2< double > &offset)
Definition Transform.h:142

Class Documentation

◆ donner::svg::compositor::CompositorController::FastPathCounters

struct donner::svg::compositor::CompositorController::FastPathCounters

Diagnostic counters for the translation-only fast path. Tests read these to assert that a drag is taking the fast path every frame, not falling through to prepareDocumentForRendering.

Class Members
uint64_t fastPathFrames = 0 Incremented every frame that takes the fast path and successfully handled every dirty entity via a compose-transform update.
uint64_t noDirtyFrames = 0 Incremented every frame where the fast-path eligibility check wasn't reached because no entities were dirty (e.g. page-load, selection-change-only frames).
uint64_t slowPathFramesWithDirty = 0 Incremented every frame whose dirty-entity set disqualified the fast path (transform+other flags, subtree with non-translation delta, missing layer, etc.) and fell through to the slow path.

◆ donner::svg::compositor::CompositorController::LayerInspectorRow

struct donner::svg::compositor::CompositorController::LayerInspectorRow

One row of diagnostic state per active compositor layer, intended for the editor's read-only layer-inspector panel (design doc 0033 M1). Cheap to build, cheap to copy: a few ints and one short string per layer.

Collaboration diagram for donner::svg::compositor::CompositorController::LayerInspectorRow:
[legend]
Class Members
Vector2i bitmapSize = Vector2i::Zero() Pixel size of the layer's cached bitmap. Vector2i::Zero() when the layer has not yet been rasterized (hasValidBitmap false).
Vector2d canvasOffset = Vector2d::Zero() Canvas-space top-left position where this layer's bitmap blits back. Vector2d::Zero() for canvas-sized layers; non-zero for intrinsic-sized layers (design doc 0033 §M2).
bool dirty = false Whether this layer is currently flagged dirty (a rasterize is pending on the next renderFrame call).
Entity entity = entt::null Root entity of the promoted subtree.
FallbackReason fallbackReasons = FallbackReason::None Raw fallback flags (handy for tests; the panel renders fallbackReasonsText for display).
string fallbackReasonsText Pre-formatted fallback flag list (e.g. "Filter | IsolatedLayer").
uint64_t generation = 0 Monotonic generation counter from CompositorLayer::generation.
bool hasValidBitmap = false Whether the layer has a valid cached bitmap.
double lastRasterizeMs = 0.0 Wall-clock duration of the most recent rasterize, in ms.
uint32_t layerId = 0 Layer's stable numeric id (CompositorLayer::id).
uint32_t rasterizeCount = 0 Cumulative rasterize count from CompositorLayer::rasterizeCount.
Vector2i thumbnailDims = Vector2i::Zero() Pixel dimensions of the downsampled thumbnail. Vector2i::Zero() when the layer has no valid bitmap. Otherwise the longer side is kLayerThumbnailMaxSide and the shorter side preserves aspect.
vector< uint8_t > thumbnailPixels RGBA8 thumbnail pixels, tightly packed (thumbnailDims.x * 4 row stride), suitable for direct upload via glTexImage2D. Empty when the layer has no valid bitmap.

◆ donner::svg::compositor::CompositorController::SegmentInspectorRow

struct donner::svg::compositor::CompositorController::SegmentInspectorRow

One row of diagnostic state per static segment (the non-promoted content between promoted layers, plus the pre-first and post-last slots). Sized N+1 where N is layerCount().

Collaboration diagram for donner::svg::compositor::CompositorController::SegmentInspectorRow:
[legend]
Class Members
Vector2i bitmapSize = Vector2i::Zero() Pixel dimensions of the cached segment bitmap. Vector2i::Zero() when the slot has no bitmap yet.
Vector2d canvasOffset = Vector2d::Zero() Canvas-space top-left offset where this segment's bitmap blits back (non-zero only on the tight-bounded path, design doc 0027).
bool dirty = false Whether this slot is currently flagged dirty (a rasterize is pending on the next renderFrame call).
uint64_t generation = 0 Monotonic per-slot generation counter.
bool hasValidBitmap = false Whether the slot has a non-empty cached bitmap.
double lastRasterizeMs = 0.0 Wall-clock duration of the most recent rasterize, in ms. Zero when this slot has never been rasterized in the current session.
size_t slotIndex = 0 Slot index (0..N inclusive). Segment 0 is the pre-first-layer content; segment N is the post-last-layer content.

◆ donner::svg::compositor::CompositorController::StaticSpanPlan

struct donner::svg::compositor::CompositorController::StaticSpanPlan

Conservative draw-cost plan for one static segment slot.

Collaboration diagram for donner::svg::compositor::CompositorController::StaticSpanPlan:
[legend]
Class Members
Box2d boundsCanvas Snapped canvas-space bounds used for immediate eligibility.
bool demotedDynamicImmediate = false True when the span was dynamically immediate last frame but this render exceeded budget, so the freshly-rendered payload is retained as a cached tile instead of staying immediate.
bool dynamicHeuristicImmediate = false True when timing expanded the span into immediate presentation.
double estimatedCacheOverheadCost = 0.0 Relative fixed/cache memory cost avoided by immediate presentation.
int estimatedDrawOps = 0 Estimated number of direct geometry draws in the span.
int estimatedPathVerbs = 0 Estimated number of path verbs across direct geometry draws.
double estimatedRedrawCost = 0.0 Relative redraw cost from tight area and geometry complexity.
uint64_t estimatedRetainedBytes = 0 Estimated presentation texture bytes retained by a cached tile.
Entity firstEntity = entt::null First render instance covered by the span, or null for an empty slot.
bool hasExpensiveEffect = false True when the span uses effects or resources that force cached-tile presentation.
double immediateBudgetChargeMs = 0.0 Budget charged by this span when it is immediate.
double immediateBudgetMs = 0.0 Total dynamic immediate-span frame budget for 120 Hz interaction.
Entity lastEntity = entt::null Last render instance covered by the span, or null for an empty slot.
double measuredRasterizeMs = 0.0 Raster time from the most recent span render.
StaticSpanMode mode = StaticSpanMode::CachedTile Presentation mode selected for this span.
size_t slotIndex = 0 Slot index in the static segment array.
string spanRangeLabel Human-readable first/last element range covered by this span.
bool staticHeuristicImmediate = false True when the static cost heuristic chose immediate presentation.
bool visible = false True when the span has a visible, bounded contribution to the canvas.

◆ donner::svg::compositor::CompositorController::RenderFrameStats

struct donner::svg::compositor::CompositorController::RenderFrameStats

Worker render costs from the most recent renderFrame call, split by whether the work was caused by immediate-mode transient spans or retained cached tiles.

Class Members
double cachedRasterizeMs = 0.0 Segment/layer raster time that produces retained cached bitmap/texture tiles.
int cachedTileCount = 0 Count of segment/layer tiles charged to cached raster work.
double immediateRasterizeMs = 0.0 Segment raster time caused by immediate-mode static spans.
int immediateTileCount = 0 Count of static spans charged to immediate raster work.

◆ donner::svg::compositor::CompositorController::StateSnapshot

struct donner::svg::compositor::CompositorController::StateSnapshot
Collaboration diagram for donner::svg::compositor::CompositorController::StateSnapshot:
[legend]
Class Members
uint32_t activeHintsCount = 0 Editor-driven explicit promotions (drag target + selection prewarm). Mandatory-detector hints don't count toward this number — they live in a separate map.
Vector2i canvasSize = Vector2i::Zero() Canvas size the compositor most recently rendered against.
Entity lastPromoteRefusalEntity = entt::null Entity the failed promoteEntity was called with. entt::null when lastPromoteRefusalReason is None.
PromoteRefusalReason lastPromoteRefusalReason = PromoteRefusalReason::None Reason the most-recent promoteEntity call returned false, or None when the most-recent call succeeded (or no call has happened yet). Sticky on failure.
uint32_t layerCount = 0 Total layers currently in layers_ (mandatory + explicit).
bool splitPathActive = false hasSplitStaticLayers() — the editor's drag-overlay fast path is active when this is true.
Entity splitStaticLayersEntity = entt::null Entity the compositor cached the bg/fg split for. entt::null when split-path is inactive.

Member Enumeration Documentation

◆ PromoteRefusalReason

Compositor-wide state useful for diagnosing why the editor's expected drag fast path didn't engage. Lets the operator confirm at a glance:

  • Did the editor's promoteEntity for the selected element actually take? → activeHintsCount == 1.
  • Is the split-bitmap optimization active? → splitPathActive.
  • Which entity is the compositor treating as the drag target? → splitStaticLayersEntity. Compare against the editor's selection in the side-panel; a mismatch means the worker and editor disagree about what's being dragged.
  • Is the canvas size what the editor expects? → canvasSize. Drops here explain "the view got pixelated after drag" type symptoms. Reason promoteEntity returned false on its most recent call. Sticky — clears only on a subsequent successful promoteEntity. Surfaced through StateSnapshot::lastPromoteRefusalReason so the editor's diagnostic panel can show "the compositor refused this promote because <reason>" without the operator having to read source.
Enumerator
InvalidEntity 

Entity was destroyed / never existed in the registry.

LayerLimit 

Too many entities already promoted (kMaxCompositorLayers).

MemoryLimit 

Total bitmap memory already at kMaxCompositorMemoryBytes.

DescendantPromoted 

A descendant already has its own promoted layer (typically a mandatorily-detected filter / mask / isolated-layer). Allowing the parent promote would double-rasterize the descendant.

Constructor & Destructor Documentation

◆ CompositorController()

donner::svg::compositor::CompositorController::CompositorController ( SVGDocument & document,
RendererInterface & renderer,
CompositorConfig config = {} )

Construct a compositor controller.

Parameters
documentThe SVG document to composite.
rendererThe renderer backend to use for rasterization and composition.
configRuntime feature gates. Default-constructed enables everything.

Member Function Documentation

◆ demoteEntity()

void donner::svg::compositor::CompositorController::demoteEntity ( Entity entity)

Demote a previously promoted entity back to the root layer.

The entity's explicit compositor hint is removed, its computed layer assignment is updated, and the layer is destroyed. The root layer is marked dirty to include the demoted entity on the next render.

Parameters
entityThe entity to demote. No-op if not currently promoted.

◆ fallbackReasonsOf()

FallbackReason donner::svg::compositor::CompositorController::fallbackReasonsOf ( Entity entity) const
nodiscard

Returns the fallback reasons for a promoted entity, or FallbackReason::None if not promoted.

Parameters
entityThe entity to query.

◆ isPromoted()

bool donner::svg::compositor::CompositorController::isPromoted ( Entity entity) const
nodiscard

Returns true if the given entity is currently promoted to its own layer.

Parameters
entityThe entity to check.

◆ layerComposeOffset()

Transform2d donner::svg::compositor::CompositorController::layerComposeOffset ( Entity entity) const
nodiscard

Returns the current bitmap-compose offset for a promoted entity's layer, or identity if the entity is not promoted or has no cached bitmap.

The compose offset is the delta between the cached bitmap's rasterize-time world transform and the entity's current absolute world transform. Callers who draw the promoted layer's bitmap independently (e.g. the editor's split-layer display path) must apply this offset so the bitmap aligns with the bg/fg render the compositor just produced.

Parameters
entityThe entity to query.

◆ promoteEntity()

PromoteResult donner::svg::compositor::CompositorController::promoteEntity ( Entity entity,
InteractionHint interactionKind = InteractionHint::ActiveDrag )

Promote an entity to its own compositor layer.

The entity and its subtree will be rasterized into a separate bitmap. During composition, the layer bitmap is blitted with its composition transform, avoiding re-rasterization of the rest of the scene.

Under CompositorConfig::autoPromoteInteractions (default on), this publishes an Interaction hint tagged with interactionKind. When the gate is off it falls back to an Explicit hint, ignoring interactionKind.

Parameters
entityThe entity to promote.
interactionKindSemantic kind for the Interaction hint. Use Selection for selection-driven pre-warm (no drag in progress) and ActiveDrag for an active user drag. Defaults to ActiveDrag for callers that only use this API during drag.
Returns
Promotion result. Valid renderable descendants under a filter, clip-path, or mask return PromoteResult::FullCanvasPreviewRequired so callers can present a full-canvas composited tile instead of treating the request as a hard failure.

◆ remapAfterStructuralReplace()

bool donner::svg::compositor::CompositorController::remapAfterStructuralReplace ( const std::unordered_map< Entity, Entity > & remap)
nodiscard

Rewire the compositor's entity-keyed state (activeHints_, mandatoryDetector_, complexityBucketer_, layers_) from the old document's entity space onto a new one, after a structurally identical setDocument.

Interaction-layer bitmaps are preserved only when the remapped layer still has a pixel-exact reuse transform and raster rectangle; otherwise the affected layer is marked dirty for the next renderFrame(). This is the fast alternative to resetAllLayers(documentReplaced=true) for the editor's drag-end writeback round-trip through ReplaceDocumentCommand: with a structurally equal reparse, the compositor can swap ids and surgically re-rasterize only caches whose pixels no longer match the settled DOM.

Parameters
remapMapping from old entity id → new entity id. Every entity in activeHints_ and in each CompositorLayer (entity, firstEntity, lastEntity) must have an entry; detectors rebuild against the new registry so their hint set doesn't need remap entries.
Returns
true on success. On false, the compositor is in an indeterminate state — the caller MUST follow up with resetAllLayers(documentReplaced=true) to recover.

◆ renderFrame() [1/3]

void donner::svg::compositor::CompositorController::renderFrame ( const RenderViewport & viewport)

Prepare and render a composited frame.

This method:

  1. Prepares the document (computes styles, layout, render tree) if needed.
  2. Checks dirty flags on promoted entities and marks their layers dirty.
  3. Re-rasterizes dirty layers via createOffscreenInstance() + drawEntityRange().
  4. Rasterizes the root layer (everything not in a promoted layer).
  5. Composes all layers in paint order via drawImage().
Parameters
viewportThe viewport for the render pass.

◆ renderFrame() [2/3]

bool donner::svg::compositor::CompositorController::renderFrame ( const RenderViewport & viewport,
CancellationToken & token )

Design doc 0033 §M4 — cancellable variant. The token is polled at coarse safe points (between rasterizeLayer / segment rasterize calls) and renderFrame returns early when set. The compositor's internal dirty flags are left intact for the work the early return skipped, so the next renderFrame picks up without re-doing already-rasterized layers / segments.

Returns true on full completion, false on early cancellation. The non-token overload above delegates with a no-op token.

◆ renderFrame() [3/3]

void donner::svg::compositor::CompositorController::renderFrame ( const RenderViewport & viewport,
const Transform2d & surfaceFromCanvas )

Prepare and render a composited frame into viewport after applying surfaceFromCanvas to canvas-space content.

Parameters
viewportThe output viewport for the render pass.
surfaceFromCanvasTransform from document canvas coordinates to the output surface.

◆ resetAllLayers()

void donner::svg::compositor::CompositorController::resetAllLayers ( bool documentReplaced = false)

Clear all layers and cached state.

Two callers, two semantics:

  • documentReplaced = false (the default, used by tests and by the compositor's own internal paths that reset against the still-live registry): runs the normal ~ScopedCompositorHint cleanup, which removes CompositorHintComponents from the live registry and lets the resolver strip the now-orphan ComputedLayerAssignment Components.
  • documentReplaced = true (used by AsyncRenderer when it detects documentGeneration has bumped, i.e. a ReplaceDocumentCommand swapped the inner SVGDocument at the same optional storage address): the old Registry was destroyed in place and a brand-new one constructed at the same address. Every ScopedCompositorHint's cached Registry* now aims at a live object that knows nothing about the old entity IDs, so calling registry.valid(old_entity) from the dtor SIGSEGVs inside entt's sparse-set lookup. In this mode the hints are release()-defused before clearing — the old CompositorHintComponents went down with the old registry anyway.

After this call, layerCount() is 0 and all cached bitmaps are released. The next renderFrame() will do a full render.

◆ setTightBoundedSegmentsEnabled()

void donner::svg::compositor::CompositorController::setTightBoundedSegmentsEnabled ( bool enabled)

Flip tight-bounded segment rasterization on or off at runtime. See CompositorConfig::tightBoundedSegments for semantics. Marks every cached static segment dirty so the next renderFrame call re-rasterizes under the new policy (otherwise the flip would affect only segments that happened to get re-rasterized for other reasons).

Intended as a bisection knob for the editor: if a visual regression seems to originate in 0027-tight_bounded_segments, flip the toggle and watch whether it disappears. Not a hot path — re-rasterizing every segment on the next frame costs one full render's worth of work.

◆ snapshotCompositeTiles()

std::vector< CompositeTileSnapshot > donner::svg::compositor::CompositorController::snapshotCompositeTiles ( SnapshotThumbnails thumbnails = SnapshotThumbnails::Include) const
nodiscard

Build the unified composite-tile snapshot in paint order. The sequence mirrors composeLayers:

  • When the split-bitmap cache is active (single editor-promoted entity): Background, Layer (drag target), Foreground. The bg/fg already subsume the static segments and non-drag layers below / above the drag entity.
  • Otherwise: Segment 0, Layer 0, Segment 1, Layer 1, …, Segment N. (Editor-facing bg/fg are inactive in this mode.)

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