Engine Initialization Guide
This guide captures the initialization flow for the native-backed chart engine and the responsibilities owned by the managed host. The APIs stabilised in this iteration are designed for low-latency, double-buffered rendering with predictable GPU resource reuse.
Prerequisites
- Copy the
vello_chart_enginenative library into the target application'sruntimes/<rid>/nativedirectory. The build scripts (scripts/build-native-*.{ps1,sh}) produce the binaries and place them underartifacts/runtimes/. - Reference the following projects from your host application:
VelloSharp(core bindings)VelloSharp.ChartEngineVelloSharp.ChartDiagnosticsVelloSharp.ChartRuntime
- Ensure
AllowUnsafeBlocksis enabled for assemblies that call the FFI surface (already set forVelloSharp.ChartEngine).
Initialization Flow
-
Instantiate the engine
var engine = new ChartEngine.ChartEngine(new ChartEngineOptions
{
VisibleDuration = TimeSpan.FromMinutes(2),
VerticalPaddingRatio = 0.08,
FrameBudget = TimeSpan.FromMilliseconds(8),
StrokeWidth = 1.5,
ShowAxes = true, // set to false to render data-only views
Palette = new[]
{
ChartColor.FromRgb(0x3A, 0xB8, 0xFF),
ChartColor.FromRgb(0xF4, 0x5E, 0x8C),
ChartColor.FromRgb(0x81, 0xFF, 0xF9),
ChartColor.FromRgb(0xFF, 0xD1, 0x4F),
},
});The constructor forwards options to the Rust engine and allocates the double-buffered scene pool.
StrokeWidthcontrols the base line thickness for all series,Paletteoverrides the default color ramp, andShowAxestoggles the time/value axes and grid rendering. -
Register render scheduling
TheRenderSchedulerremains in managed code to integrate with UI frameworks:engine.ScheduleRender(tick =>
{
// Typically call RequestRender on the hosting view
}); -
Publish streaming samples
CallPumpDatawith time-series spans. Samples are forwarded to the native data pipeline using a stack-allocated fast path for small bursts.engine.PumpData(samples); // samples is ReadOnlySpan<ChartSamplePoint> -
Render into the provided scene
When the host view requests a frame, callRenderwith the scene supplied byVelloView.engine.Render(context.Scene, context.Width, context.Height);The native engine writes into its double-buffered
Sceneobjects and appends the active buffer into the managed scene handle. -
Consume diagnostics
FrameDiagnosticsCollectoris updated with each frame. You can queryengine.LastFrameStatsor subscribe to the recorded histograms for telemetry.
Runtime Styling Overrides
- Update the palette without tearing down the engine:
// Passing Span<T> lets you reuse buffers or slice existing theme data
engine.UpdatePalette(stackalloc[]
{
ChartColor.FromRgb(0x2F, 0x95, 0xFF),
ChartColor.FromRgb(0xF9, 0x65, 0x7D),
ChartColor.FromRgb(0x4E, 0xC9, 0x74),
});
// Revert to the built-in palette
engine.UpdatePalette(ReadOnlySpan<ChartColor>.Empty); - Apply per-series overrides for labels, thickness, and colors without recreating the engine:
Overrides are tri-state: call
Span<ChartSeriesOverride> overrides = stackalloc[]
{
new ChartSeriesOverride(seriesId: 1)
.WithLabel("Bid")
.WithStrokeWidth(2.0)
.WithColor(ChartColor.FromRgb(0x3A, 0xB8, 0xFF)),
new ChartSeriesOverride(seriesId: 2)
.WithLabel("Ask")
.ClearStrokeWidth()
.WithColor(ChartColor.FromRgb(0xF4, 0x5E, 0x8C)),
};
engine.ApplySeriesOverrides(overrides);Clear*helpers to remove an override and fall back to the shared defaults.
Configuring Series Definitions
- Declare the rendering behaviour for each series up front. Definitions drive legend markers, overlay styling, and how the native engine builds GPU buffers.
engine.ConfigureSeries(new ChartSeriesDefinition[]
{
new LineSeriesDefinition(0)
{
StrokeWidth = 2.0,
FillOpacity = 0.18,
},
new ScatterSeriesDefinition(1)
{
MarkerSize = 6.0,
},
new BarSeriesDefinition(2)
{
Baseline = 0,
BarWidthSeconds = 6.0,
},
}); - Series that are not explicitly configured fall back to the line rendering defaults.
GPU Surface Hosting
ChartViewnow composesVelloSurfaceView, so GPU swapchains are attached automatically when supported by the platform window handle.- Surface resizing and presentation are handled by the shared host; the control transparently falls back to the bitmap path when hardware acceleration is unavailable.
- Surface tuning remains accessible via the regular properties:
ChartHost.RendererOptions = ChartHost.RendererOptions with { BaseDpi = new Vector2(96f, 96f) };
ChartHost.RenderParameters = ChartHost.RenderParameters with { BaseColor = RgbaColor.FromBytes(0x10, 0x15, 0x1F) };
Axes and Grid
- The engine now computes a shared viewport for all series and renders labelled time/value axes with adaptive tick spacing.
- Grid lines inherit those ticks, giving trading dashboards quick alignment cues without extra overlay code.
- Axes consume dynamic padding around the plot. When you set
ShowAxes = false, the chart expands to the full control bounds for sparkline layouts.
Diagnostics and Tracing
- The Rust engine emits
tracingevents which are bridged to.NETviaChartEngineEventSource. Consumers can listen with ETW/EventSource listeners orEventListener. - The trace pipeline is best-effort; if the callback registration fails the engine continues without raising exceptions.
Renderer Pooling
The Avalonia host (ChartView) relies on VelloSurfaceView for GPU presentation. The Rust engine reuses internal Scene buffers, and the managed layer keeps the VelloSurfaceView renderer pool hot, ensuring command buffers and textures are recycled every frame.
Disposal Semantics
Always dispose the engine from the UI thread that owns the scheduler:
engine.Dispose();
Disposal tears down the scheduler, diagnostics collectors, and the native handle in one pass.
Next Steps
- Extend the EventSource listener to forward metrics into application-level telemetry.
- Combine runtime palette updates with per-series overrides to drive live theming or interaction-driven callouts.
- Incorporate structured tracing IDs once additional spans are stabilised on the Rust side.