VelloSharp.Skia.Core
0.5.0-alpha.2
dotnet add package VelloSharp.Skia.Core --version 0.5.0-alpha.2
NuGet\Install-Package VelloSharp.Skia.Core -Version 0.5.0-alpha.2
<PackageReference Include="VelloSharp.Skia.Core" Version="0.5.0-alpha.2" />
<PackageVersion Include="VelloSharp.Skia.Core" Version="0.5.0-alpha.2" />
<PackageReference Include="VelloSharp.Skia.Core" />
paket add VelloSharp.Skia.Core --version 0.5.0-alpha.2
#r "nuget: VelloSharp.Skia.Core, 0.5.0-alpha.2"
#:package VelloSharp.Skia.Core@0.5.0-alpha.2
#addin nuget:?package=VelloSharp.Skia.Core&version=0.5.0-alpha.2&prerelease
#tool nuget:?package=VelloSharp.Skia.Core&version=0.5.0-alpha.2&prerelease
VelloSharp .NET bindings
This repository hosts the managed bindings that expose the Linebender graphics stack—vello
for rendering, wgpu
for portable GPU access, winit
for cross-platform windowing, peniko
/kurbo
for brush and geometry data, and the text pipeline built on
parley
, skrifa
, swash
, and fontique
—to .NET applications. VelloSharp
wraps these native crates together
with AccessKit
so scene building, surface presentation, input, accessibility, and text
layout share a cohesive managed API while still exposing low-level control over wgpu
devices, queues, and surfaces.
NuGet packages
Managed bindings
Native runtime packages
Each native package has runtime-specific variants (for example VelloSharp.Native.Vello.win-x64
) that are published alongside the platform-agnostic meta-package. When you reference the meta-package, dotnet restore
automatically selects the correct RID-specific asset.
The codebase is split into native FFI crates, managed bindings, integration helpers, and sample applications:
- Native FFI crates (under
ffi/
):ffi/vello_ffi
– wraps the renderer, shader, SVG, Velato/Lottie, text, and wgpu stacks behind a single C ABI, including surface/swapchain helpers for GPU presentation.ffi/peniko_ffi
– bridges paint/brush data so gradients, images, and style metadata can be inspected or constructed from managed code.ffi/kurbo_ffi
– exposes the geometry primitives used across the stack (affine transforms, Bézier paths, and bounding-box helpers) without pulling in the full Rust curve library.ffi/winit_ffi
– forwards windowing, input, and swap-chain negotiation so native event loops can be driven from .NET when desired.ffi/accesskit_ffi
– serialises/deserialises AccessKit tree updates and action requests so accessibility data can flow between managed code and platform adapters.ffi/gauges-core
– foundational scene hooks for industrial gauges, exposing a shared initialization point for the managed gauge controls.ffi/scada-runtime
– SCADA runtime bootstrap layer that will surface alarm/state orchestration to managed dashboards.ffi/editor-core
– entry points for the unified visual editor, enabling design-time composition features over the shared runtime.
- Managed assemblies (under
bindings/
):VelloSharp
- idiomatic C# wrappers for all native exports: scenes, fonts, images, surface renderers, the wgpu device helpers, and theKurboPath
/KurboAffine
andPenikoBrush
utilities.VelloSharp.Windows.Core
- shared Windows GPU plumbing (device/queue leasing, diagnostics, swapchain helpers, D3D11 ↔ D3D9 interop) used by WinForms and WPF hosts.VelloSharp.Integration.Wpf
- WPF controls (VelloView
,VelloNativeSwapChainView
) with composition-based rendering, keyed-mutex coordination, diagnostics, and backend switching.VelloSharp.Integration.WinForms
- WinForms control hosting that now delegates GPU lifetime management toVelloSharp.Windows.Core
.VelloSharp.WinForms.Core
- Windows Forms drawing surface abstractions (Graphics
,Pen
,Brush
,Region
) powered by the shared renderer.VelloSharp.Skia
- a Skia-inspired helper layer that mapsSKCanvas
/SKPath
-style APIs onto Vello primitives for easier porting of existing SkiaSharp code.VelloSharp.Integration
- optional helpers for Avalonia, SkiaSharp interop, and render-path negotiation (ship viadotnet add package VelloSharp.Integration
).VelloSharp.Avalonia.Winit
- Avalonia host glue that drives the winit-based surface renderer through the managed bindings.VelloSharp.Avalonia.Vello
- Avalonia platform abstractions that adapt Vello surfaces and inputs into application-friendly controls.
- Application assemblies (under
src/
):VelloSharp.Composition
- composition primitives, plotting surfaces, and shared utilities consumed by higher-level dashboards.VelloSharp.ChartData
- streaming data buses and sample buffers for real-time charts.VelloSharp.ChartDiagnostics
- telemetry collectors and instrumentation helpers for chart runtimes.VelloSharp.ChartRuntime
- scheduler, tick sources, and execution helpers shared by chart hosts.VelloSharp.ChartRuntime.Windows
- Windows-specific dispatcher, swapchain, and composition integrations for charts.VelloSharp.ChartEngine
- animation loops, color utilities, and renderer orchestrators for charts.VelloSharp.Charting
- chart composition API, styling, axes, and legend utilities.VelloSharp.Charting.Avalonia
- Avalonia UI controls and adapters that host the chart engine.VelloSharp.Charting.WinForms
- WinForms chart controls backed by the shared runtime.VelloSharp.Charting.Wpf
- WPF chart host controls with accessibility and overlay support.VelloSharp.Gauges
- industrial gauge primitives backed by the native gauges runtime.VelloSharp.Scada
- SCADA runtime, alarms, and dashboard orchestration services.VelloSharp.TreeDataGrid
- interop layer around the native tree data grid renderer.VelloSharp.Editor
- managed hooks for the editor core and composition tooling.
Managed package quickstart
The managed packages are designed to be composed as needed. Use the snippets below as a starting point for each package.
VelloSharp
- Builds scenes, drives the renderer, and manages images, fonts, and brushes.
- Combine with the native packages to target GPU, CPU, or sparse pipelines.
using System.Numerics;
using VelloSharp;
using var scene = new Scene();
var path = new PathBuilder()
.MoveTo(0, 0)
.LineTo(128, 0)
.LineTo(64, 96)
.Close();
scene.FillPath(path, FillRule.NonZero, Matrix3x2.Identity, RgbaColor.FromBytes(0, 128, 255, 255));
using var renderer = new Renderer(128, 96);
var buffer = new byte[128 * 96 * 4];
var renderParams = new RenderParams(128, 96, RgbaColor.FromBytes(0, 0, 0, 255));
renderer.Render(scene, renderParams, buffer, 128 * 4);
VelloSharp.Core
- Supplies shared primitives such as
PathBuilder
,RenderParams
, gradients, and stroke styles. - Acts as the foundation for every other managed package.
using System.Numerics;
using VelloSharp;
var brush = new LinearGradientBrush((0, 0), (0, 200),
GradientStop.At(0f, RgbaColor.FromBytes(255, 0, 0, 255)),
GradientStop.At(1f, RgbaColor.FromBytes(0, 0, 255, 255)));
var path = new PathBuilder()
.MoveTo(32, 32)
.QuadraticTo(128, 0, 224, 128)
.Close();
VelloSharp.Ffi.Core
- Exposes raw structs/enums for window handles, colours, brushes, and status codes.
- Useful when interoperating with native surfaces or marshalling custom handles.
using System;
using VelloSharp;
IntPtr hwnd = /* obtain your HWND (for example via Form.Handle) */;
IntPtr hinstance = /* retrieve the module handle associated with that window */;
var win32Handle = SurfaceHandle.FromWin32(hwnd, hinstance);
var descriptor = new SurfaceDescriptor
{
Width = 1920,
Height = 1080,
PresentMode = PresentMode.AutoVsync,
Handle = win32Handle,
};
VelloSharp.Ffi.Gpu
- Provides the P/Invoke entry points used by the GPU renderer (
vello_ffi
) and wgpu helpers. - Includes
GpuNativeHelpers.ThrowOnError
for consistent error translation.
using System;
using VelloSharp;
var rendererHandle = NativeMethods.vello_renderer_create(800, 600);
if (rendererHandle == IntPtr.Zero)
{
throw new InvalidOperationException(NativeHelpers.GetLastErrorMessage() ?? "Renderer creation failed.");
}
NativeMethods.vello_renderer_destroy(rendererHandle);
VelloSharp.Ffi.Sparse
- Direct bridge to the sparse CPU renderer (
vello_sparse_ffi
) without the managed wrapper. - Ideal for embedding the SIMD-aware renderer inside existing native pipelines.
using System;
using VelloSharp;
var context = SparseNativeMethods.vello_sparse_render_context_create(640, 480);
try
{
SparseNativeHelpers.ThrowOnError(
SparseNativeMethods.vello_sparse_render_context_set_aliasing_threshold(context, 4),
nameof(SparseNativeMethods.vello_sparse_render_context_set_aliasing_threshold));
}
finally
{
SparseNativeMethods.vello_sparse_render_context_destroy(context);
}
VelloSharp.Text
- Wraps text shaping, OpenType features, and variation axes with friendly record structs.
- Complements both the GPU and sparse renderers.
using VelloSharp.Text;
var options = VelloTextShaperOptions.CreateDefault(fontSize: 18f, isRightToLeft: false) with
{
Features = new[] { new VelloOpenTypeFeature("liga", 1) },
VariationAxes = new[] { new VelloVariationAxisValue("wght", 600f) },
};
VelloSharp.HarfBuzzSharp
- Provides a HarfBuzzSharp-compatible API surface backed by
VelloSharp.Text
, keeping existing text pipelines intact. - Ideal for Avalonia or SkiaSharp integrations that expect
HarfBuzzSharp
assemblies while shaping through Vello.
using HarfBuzzSharp;
using var blob = Blob.FromFile("Assets/Fonts/Roboto-Regular.ttf");
using var face = new Face(blob, 0);
using var font = new Font(face);
using var buffer = new Buffer();
buffer.AddUtf8("VelloSharp");
buffer.GuessSegmentProperties();
font.Shape(buffer);
VelloSharp.Integration
- Supplies Avalonia controls (such as
VelloView
), render-path negotiation, and cross-platform hosting utilities shared by UI integrations. - Centralises renderer lifecycle management so Skia, Avalonia, and Windows hosts can swap pipelines with one package reference.
using Avalonia;
using VelloSharp.Integration.Avalonia;
AppBuilder.Configure<App>()
.UsePlatformDetect()
.UseVelloSkiaTextServices()
.StartWithClassicDesktopLifetime(args);
VelloSharp.Gpu
- Adds higher-level GPU utilities, AccessKit helpers, and native library registration.
- Automatically registers native DLLs through
NativeLibraryLoader
.
using VelloSharp;
var request = AccessKitActionRequest.FromJson("{\"type\":\"Focus\",\"action_request_id\":1}");
using var document = request.ToJsonDocument();
Console.WriteLine(document.RootElement.GetProperty("type").GetString());
VelloSharp.Skia.Core
- Recreates SkiaSharp-style APIs (
SKSurface
,SKCanvas
,SKPaint
, etc.) backed by Vello scenes. - Perfect when porting Skia drawing code onto the Vello renderer.
using SkiaSharp;
var surface = SKSurface.Create(new SKImageInfo(256, 256));
surface.Canvas.Clear(SKColors.White);
using var paint = new SKPaint { Color = SKColors.DarkOrange, IsAntialias = true };
surface.Canvas.DrawCircle(128, 128, 96, paint);
surface.Flush();
VelloSharp.Skia.Gpu
- Registers the GPU-enabled backend via module initialisers—no extra code required.
- Once referenced, Skia surfaces render via Vello + wgpu automatically.
using SkiaSharp;
var gpuSurface = SKSurface.Create(new SKImageInfo(1024, 512));
gpuSurface.Canvas.DrawRect(SKRect.Create(0, 0, 1024, 512), new SKPaint { Color = SKColors.CornflowerBlue });
gpuSurface.Flush();
VelloSharp.Skia.Cpu
- Provides the sparse/CPU backend for the Skia integration.
- Reference alongside
VelloSharp.Skia.Core
to guarantee deterministic software rendering.
using SkiaSharp;
var cpuSurface = SKSurface.Create(new SKImageInfo(400, 200));
cpuSurface.Canvas.DrawText("CPU sparse", 20, 120, new SKPaint { Color = SKColors.Black, TextSize = 48 });
cpuSurface.Flush();
VelloSharp.Integration.Skia
- Offers
SkiaRenderBridge
to stream Vello render buffers into Skia bitmaps or surfaces. - Ideal for hybrid dashboards that mix Skia UI with Vello scenes.
using SkiaSharp;
using System.Numerics;
using VelloSharp;
using VelloSharp.Integration.Skia;
using VelloSharp.Rendering;
using var scene = new Scene();
scene.FillPath(new PathBuilder().MoveTo(0, 0).LineTo(256, 0).LineTo(256, 256).Close(), FillRule.NonZero, Matrix3x2.Identity, RgbaColor.Crimson);
using var surface = SKSurface.Create(new SKImageInfo(256, 256));
using var renderer = new Renderer(256, 256);
var renderParams = new RenderParams(256, 256, RgbaColor.FromBytes(0, 0, 0, 255));
SkiaRenderBridge.Render(surface, renderer, scene, renderParams);
surface.Flush();
VelloSharp.Avalonia.Vello
- Hooks the Vello renderer into Avalonia via
AppBuilder.UseVello
. - Exposes
VelloPlatformOptions
for FPS caps, clear colours, and antialiasing.
using Avalonia;
using VelloSharp.Avalonia.Vello;
AppBuilder.Configure<App>()
.UsePlatformDetect()
.UseVello(new VelloPlatformOptions { FramesPerSecond = 120 })
.StartWithClassicDesktopLifetime(args);
VelloSharp.Avalonia.Winit
- Registers the winit windowing subsystem for Avalonia (
AppBuilder.UseWinit
). - Combine with
VelloSharp.Avalonia.Vello
to run entirely on winit + Vello.
using Avalonia;
using VelloSharp.Avalonia.Winit;
AppBuilder.Configure<App>()
.UseWinit()
.StartWithClassicDesktopLifetime(args);
VelloSharp.Avalonia.Controls
VelloCanvasControl
exposes the rawScene
via theDraw
event so you can record Vello commands directly in Avalonia layouts.VelloAnimatedCanvasControl
adds a managed render loop withTotalTime
/DeltaTime
tracking for kinetic compositions and dashboards.VelloSvgControl
keeps vector artwork crisp by renderingVelloSvg
documents from streams, strings, or Avalonia resources.
<controls:VelloCanvasControl Draw="OnCanvasDraw"
xmlns:controls="clr-namespace:VelloSharp.Avalonia.Controls;assembly=VelloSharp.Avalonia.Controls"/>
private void OnCanvasDraw(object? sender, VelloDrawEventArgs e)
{
var scene = e.Scene;
var transform = e.GlobalTransform;
var bounds = e.Bounds;
var backdrop = new PathBuilder()
.MoveTo(bounds.X, bounds.Y)
.LineTo(bounds.Right, bounds.Y)
.LineTo(bounds.Right, bounds.Bottom)
.LineTo(bounds.X, bounds.Bottom)
.Close();
scene.FillPath(backdrop, FillRule.NonZero, transform, new SolidColorBrush(RgbaColor.FromBytes(16, 22, 35)));
}
See samples/AvaloniaVelloControlsSample
for a full walkthrough covering custom drawing, animation, and SVG hosting.
VelloSharp.Windows.Core
- Supplies
VelloGraphicsDevice
, swapchain helpers, and diagnostics events for Windows hosts. - Shared foundation for both WinForms and WPF integrations.
using VelloSharp.Windows;
using var device = new VelloGraphicsDevice(1920, 1080);
using var session = device.BeginSession(1920, 1080);
Console.WriteLine($"Surface size: {session.Width}x{session.Height}");
VelloSharp.WinForms.Core
- Adds WinForms-oriented helpers such as
VelloBitmap
that wrapSystem.Drawing.Bitmap
. - Simplifies producing
ImageBrush
payloads from WinForms painting code.
using System.Drawing;
using VelloSharp.WinForms;
var bitmap = new Bitmap(256, 256, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
using var velloBitmap = VelloBitmap.FromBitmap(bitmap);
Console.WriteLine($"Vello image size: {velloBitmap.Width}x{velloBitmap.Height}");
VelloSharp.Integration.WinForms
- Ships
VelloRenderControl
, a drop-in WinForms control with render-loop management. - Attach to
PaintSurface
to draw scenes on demand or continuously.
using System.Windows.Forms;
using VelloSharp.WinForms.Integration;
var control = new VelloRenderControl { Dock = DockStyle.Fill };
control.PaintSurface += (_, e) =>
{
// Build your scene with e.Session.Scene and render via e.Session.Renderer.
};
var form = new Form { Text = "VelloSharp WinForms" };
form.Controls.Add(control);
Application.Run(form);
VelloSharp.Integration.Wpf
- Provides
VelloNativeSwapChainView
for WPF swapchain hosting with GPU/CPU fallbacks. - Exposes events (
PaintSurface
,RenderSurface
) for custom rendering logic.
<Window x:Class="VelloDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vello="clr-namespace:VelloSharp.Wpf.Integration;assembly=VelloSharp.Integration.Wpf"
Title="VelloSharp WPF" Height="450" Width="800">
<vello:VelloNativeSwapChainView RenderMode="Continuous"
PreferredBackend="Gpu"
RenderSurface="OnRenderSurface" />
</Window>
VelloSharp.Uno
- Integrates Vello rendering into Uno Platform controls and diagnostics tooling.
- Handy when projecting Vello scenes into WinUI or XAML Islands.
using VelloSharp.Uno.Controls;
var panel = new VelloSwapChainPanel();
((IVelloDiagnosticsProvider)panel).DiagnosticsUpdated += (_, e) =>
{
Console.WriteLine($"GPU presentations: {e.Diagnostics.SwapChainPresentations}");
};
VelloSharp.Windows.Shared (preview)
- Shared
VelloSwapChainPresenter
, diagnostics, dispatcher, and AccessKit host helpers reused by WinUI, UWP, Uno, and MAUI bindings. - Targets
net8.0-windows10.0.17763
today and ships AppContainer-safe dispatcher abstractions consumed by the UWP control.
using VelloSharp.Windows.Shared.Presenters;
var presenter = new VelloSwapChainPresenter(host, surfaceSource);
presenter.OnLoaded();
presenter.RequestRender();
VelloSharp.WinUI (preview)
VelloSwapChainControl
is a WinUI 3SwapChainPanel
that renders Vello scenes with full GPU acceleration.- See
samples/WinUIVelloGallery
for an animated example and diagnostics overlay.
<Grid xmlns:vello="using:VelloSharp.Windows.Controls">
<vello:VelloSwapChainControl x:Name="SwapChain"
PreferredBackend="Gpu"
RenderMode="Continuous" />
</Grid>
SwapChain.PaintSurface += (_, e) =>
{
var scene = e.Session.Scene;
scene.Reset();
var rect = new PathBuilder()
.MoveTo(0, 0).LineTo(e.Session.Width, 0)
.LineTo(e.Session.Width, e.Session.Height).LineTo(0, e.Session.Height)
.Close();
scene.FillPath(rect, FillRule.NonZero, Matrix3x2.Identity, new RgbaColor(0.2f, 0.3f, 0.65f, 1f));
};
VelloSharp.Uwp (preview)
VelloSwapChainPanel
now mirrors the WinUI control with D3D12/Vulkan backends, WARP fallback, diagnostics, and AccessKit automation peers for UIA/AppContainer scenarios.- Targets
net8.0-windows10.0.19041
(WinAppSDK) today; theuap10.0.19041
packaging target remains tracked indocs/winui-uwp-vello-full-gpu-integration-plan.md
.
<Grid xmlns:vello="using:VelloSharp.Uwp.Controls">
<vello:VelloSwapChainPanel x:Name="SwapChain"
PreferredBackend="Gpu"
RenderMode="OnDemand" />
</Grid>
VelloSharp.Composition
- Shared composition primitives for dashboards, gauges, and SCADA shells.
- Supplies geometry metrics and layout helpers consumed across the runtime.
using VelloSharp.Composition;
var metrics = new LabelMetrics(width: 120, height: 24, baseline: 18);
Console.WriteLine($"Label metrics {metrics.Width}x{metrics.Height}");
VelloSharp.ChartData
- Lock-free data buses for streaming telemetry into chart scenes.
- Works with
Span<T>
sources for minimal allocations.
using VelloSharp.ChartData;
var bus = new ChartDataBus(capacity: 4);
bus.Write(new[] { 1.0f, 2.5f, 3.75f });
if (bus.TryRead(out var slice))
{
Console.WriteLine($"Slice items: {slice.ItemCount}");
slice.Dispose();
}
VelloSharp.ChartDiagnostics
- Records frame statistics and exposes them through .NET diagnostics APIs.
- Pipe metrics into
Meter
,Activity
, or custom sinks.
using System;
using VelloSharp.ChartDiagnostics;
using var collector = new FrameDiagnosticsCollector();
collector.Record(new FrameStats(TimeSpan.FromMilliseconds(4.2), TimeSpan.FromMilliseconds(3.1), TimeSpan.FromMilliseconds(1.0), 128, DateTimeOffset.UtcNow));
VelloSharp.ChartEngine
- The real-time chart renderer built on Vello primitives.
- Provides animation profiles, color spaces, and composition hooks.
using VelloSharp.ChartEngine;
var profile = ChartAnimationProfile.Default with { ReducedMotionEnabled = true };
var color = ChartColor.FromRgb(34, 139, 230);
VelloSharp.Charting
- High-level chart composition API, axes, legends, and styling utilities.
- Builds on the engine to define complete dashboard layouts.
using VelloSharp.Charting.Layout;
var orientation = AxisOrientation.Left;
Console.WriteLine($"Axis orientation: {orientation}");
VelloSharp.Charting.Avalonia
- Avalonia controls (
ChartView
) that host the chart engine. - Integrates with Avalonia's styling, input, and dispatcher model.
using VelloSharp.Charting.Avalonia;
var chartView = new ChartView();
VelloSharp.Charting.WinForms
- Windows Forms control hosting the chart runtime.
- Designed for drop-in use in existing WinForms dashboards.
using System;
using VelloSharp.Charting.WinForms;
[STAThread]
using var control = new ChartView();
VelloSharp.Charting.Wpf
- WPF
ChartView
that wires the chart engine into a swapchain-backed control. - Supports accessibility, composition overlays, and backend switching.
using VelloSharp.Charting.Wpf;
var control = new ChartView();
VelloSharp.ChartRuntime
- Scheduling primitives, frame tick sources, and render-loop helpers.
- Shared by Avalonia, WinForms, and WPF chart hosts.
using System;
using VelloSharp.ChartRuntime;
var scheduler = new RenderScheduler(TimeSpan.FromMilliseconds(16), TimeProvider.System);
VelloSharp.ChartRuntime.Windows
- Windows-specific tick sources and dispatcher integrations for charts.
- Provides WinForms and WinUI composition helpers.
using System.Windows.Forms;
using VelloSharp.ChartRuntime.Windows.WinForms;
using var control = new Control();
using var tickSource = new WinFormsTickSource(control);
VelloSharp.Gauges
- Managed bridge to the native gauges runtime.
- Ensure the native module is loaded before rendering gauges.
using VelloSharp.Gauges;
GaugeModule.EnsureInitialized();
VelloSharp.Editor
- Initializes the native editor core used by the visual editor shell.
using VelloSharp.Editor;
EditorRuntime.EnsureInitialized();
VelloSharp.Scada
- SCADA dashboards, alarm orchestration, and runtime shell helpers.
using VelloSharp.Scada;
ScadaRuntime.EnsureInitialized();
VelloSharp.TreeDataGrid
- Native-backed tree data grid model for hierarchical telemetry.
using VelloSharp.TreeDataGrid;
using var model = new TreeDataModel();
model.AttachRoots(new[] { new TreeNodeDescriptor(1, TreeRowKind.Data, 24f, hasChildren: false) });
- Samples:
samples/AvaloniaVelloWinitDemo
- minimal Avalonia desktop host covering CPU and GPU render paths through the AvaloniaNative/Vello stack.samples/AvaloniaVelloX11Demo
- Linux-focused host that locks Avalonia to the X11 platform for backend validation.samples/AvaloniaVelloWin32Demo
- Windows host configured for the Win32 platform while exercising the Vello renderer.samples/AvaloniaVelloNativeDemo
- macOS host forced onto AvaloniaNative to vet the Vello integration end-to-end.samples/AvaloniaVelloExamples
- expanded scene catalogue with renderer option toggles and surface fallbacks.samples/AvaloniaVelloControlsSample
- quick tour of the reusable canvas, animation, and SVG controls.samples/AvaloniaVelloSkiaSharpSample
- SkiaSharp shim gallery spanning lease-driven surfaces, SKCodec workflows, runtime effect editing, and geometry boolean operations across CPU/GPU backends.samples/AvaloniaSkiaMotionMark
- a side-by-side Skia/Vello motion-mark visualiser built on the integration layer.samples/AvaloniaSkiaSparseMotionMarkShim
- CPU sparse MotionMark shim that routes Vello scenes through the Velato Skia bridge without touching the GPU backend.samples/MauiVelloGallery
- .NET MAUI gallery hosting the newVelloView
; GPU animation now runs on Windows and ships in preview on MacCatalyst/iOS/Android via the new Metal/Vulkan presenters. The MAUI handler exposesSuppressGraphicsViewCompositor
so applications can disable the fallback Skia compositor while Vello owns the swapchain.samples/VelloSharp.WpfSample
- WPF composition host showcasingVelloView
, backend toggles, diagnostics binding, and a MotionMark fast-path page driven through the new GPU render-surface API.samples/WinFormsMotionMarkShim
- Windows Forms MotionMark GPU shim built atop the shared Windows GPU context, demonstratingVelloRenderControl
, theRenderSurface
fast path, backend switching, and DPI-aware swapchain handling.
Quick start builds
Run these from the repository root to go from a clean clone to native artifacts and managed binaries.
Windows (PowerShell)
pwsh -ExecutionPolicy Bypass -File scripts\bootstrap-windows.ps1
pwsh -File scripts\build-native-windows.ps1
dotnet build VelloSharp.sln -c Release
pwsh -File scripts\copy-runtimes.ps1
macOS (bash/zsh)
./scripts/bootstrap-macos.sh
./scripts/build-native-macos.sh
dotnet build VelloSharp.sln -c Release
./scripts/copy-runtimes.sh
Linux (bash)
./scripts/bootstrap-linux.sh
./scripts/build-native-linux.sh
dotnet build VelloSharp.sln -c Release
./scripts/copy-runtimes.sh
Each build-native-*
script compiles every FFI crate and stages the libraries under artifacts/runtimes/<rid>/native/
. The copy script fans the native payloads into the managed project bin/
folders so the samples can run immediately. On Windows it also mirrors the runtimes into net8.0-windows
outputs so the WinForms shim and MotionMark sample work out of the box.
WPF integration
VelloSharp.Integration.Wpf
provides a composition-first hosting experience that aligns with the shared Windows GPU stack introduced in VelloSharp.Windows.Core
. Key capabilities include:
VelloView
, a WPFDecorator
that renders into aD3DImage
using shared textures, honoursRenderMode
,PreferredBackend
, andRenderLoopDriver
, and exposes a bindableDiagnostics
property (frame-rate smoothing, swapchain/device reset counters, keyed mutex contention).VelloNativeSwapChainView
, an opt-in HWND swapchain host for diagnostics, exclusive full-screen scenarios, or interop with other DirectX components.- Automatic leasing of the shared GPU context across multiple controls, render suspension based on visibility, window state, or application activation, and keyed-mutex fallbacks with detailed diagnostics sourced from
VelloSharp.Windows.Core
. - Both
VelloView
and the WinFormsVelloRenderControl
expose aRenderSurface
event (viaVelloSurfaceRenderEventArgs
) so advanced callers can feed pre-recorded scenes or custom render graphs straight into the underlyingRenderer
and target surface.
The WinForms integration now consumes the very same shared Windows GPU primitives, so both VelloRenderControl
and VelloView
participate in the unified leasing, diagnostics, and asset-copy workflows. Refer to samples/VelloSharp.WpfSample
for an end-to-end MVVM-friendly example that binds diagnostics, toggles render backends, and demonstrates clean suspension/resume behaviour.
Developer setup
Bootstrap the native toolchains and Rust before building the FFI crates or running the packaging scripts:
scripts/bootstrap-linux.sh
installs the required build essentials, GPU/windowing headers, and rustup on Debian/Ubuntu, Fedora, Arch, and openSUSE systems (run with sudo or as root).scripts/bootstrap-macos.sh
ensures the Xcode Command Line Tools, Homebrew packages (CMake, Ninja, pkg-config, LLVM, Python), and rustup are installed.scripts/bootstrap-windows.ps1
must be executed from an elevated PowerShell session; it installs Visual Studio Build Tools, CMake, Ninja, Git, and rustup via winget/Chocolatey when available.
Each script is idempotent and skips packages that are already present.
Rust dependency reference
The FFI crates (vello_ffi
, peniko_ffi
, kurbo_ffi
, winit_ffi
, accesskit_ffi
) share the same high-level
dependencies from the vendored Vello workspace. The table summarises the crates you interact with most when
updating or auditing the bindings:
Dependency | Role in the bindings |
---|---|
vello |
Core renderer that powers all scene, surface, and GPU/CPU pipelines exposed through vello_ffi . |
wgpu |
Graphics abstraction used to request adapters, devices, and swapchains for the GPU-backed render paths. |
vello_svg & velato |
Asset loaders surfaced via the FFI for SVG scenes and Lottie/After Effects playback. |
peniko & kurbo |
Brush, gradient, and geometry primitives re-exported in managed code for path building. |
skrifa , swash , parley , fontique |
Font parsing, shaping, and layout stack that feeds glyph runs into Vello. |
accesskit & accesskit_winit |
Accessibility tree interchange, shared with the Avalonia integrations. |
winit & raw-window-handle |
Window/event loop abstractions used by winit_ffi and the Avalonia platform glue. |
wgpu-profiler , pollster , futures-intrusive |
Utilities that bridge async renderer calls and surface GPU timings through the bindings. |
WGPU integration
VelloSharp
ships first-class wrappers for the wgpu
API so .NET applications can configure adapters, devices, and
surfaces directly before handing targets to the renderer. The binding layer mirrors the Rust API surface closely:
WgpuInstance
,WgpuAdapter
,WgpuDevice
, andWgpuQueue
map one-to-one with the native objects and expose all safety checks viaIDisposable
lifetimes.SurfaceHandle.FromWin32
,.FromAppKit
,.FromWayland
, and.FromXlib
let you construct swapchains from any window handle obtained viawinit_ffi
or Avalonia'sINativePlatformHandleSurface
.WgpuSurface
configuration accepts the full backend matrix (DX12, Metal, Vulkan, or GLES) so the renderer can adopt whatever the host platform supports without recompiling native code.WgpuTexture
,WgpuCommandEncoder
, andWgpuBuffer
bindings make it feasible to interleave custom compute or upload work with Vello's own render passes when you need advanced scenarios.
The higher-level helpers in VelloSharp.Integration
build on these primitives: Avalonia controls negotiate
swapchains through the same APIs, while the profiler hooks exposed by wgpu-profiler
surface GPU timings back to
managed code. If you prefer a software path, the bindings can skip wgpu
entirely and fall back to CPU rendering
without changing the managed API surface.
Project status
- FFI crates –
vello_ffi
,peniko_ffi
,winit_ffi
, andaccesskit_ffi
expose 100% of their exported functions to .NET.kurbo_ffi
is feature-complete for the bindings in this repository, with only six geometry helpers intentionally left unbound (seedocs/ffi-api-coverage.md
). Native builds are validated across Windows, macOS, Linux, Android, iOS, and WebAssembly RIDs, and they share the samecargo
feature flags as upstream Vello. - Managed bindings –
VelloSharp
surfaces the full renderer, scene graph, surface contexts, glyph and image helpers, SVG/Velato decoders, and the wgpu device/surface management APIs. Disposable wrappers and span validators guard the native lifetimes, and theRendererOptions
/RenderParams
mirrors keep behaviour in sync with the Rust implementation. - Integration libraries -
VelloSharp.Windows.Core
centralises Windows-specific GPU context leasing, diagnostics, and swapchain/texture interop that are now consumed by both WinForms and WPF.VelloSharp.Integration.Wpf
introduces the composition-basedVelloView
, the opt-inVelloNativeSwapChainView
, keyed-mutex management, and bindable diagnostics, whileVelloSharp.Integration.WinForms
reuses the same core forVelloRenderControl
and MotionMark shims. Cross-platform glue continues to live inVelloSharp.Integration
(Avalonia helpers, Skia bridges), withVelloSharp.Avalonia.*
layering in the winit event loop bridge and Avalonia platform abstractions. - Samples and tooling – the Avalonia demos ship with automated runtime asset copying, configurable frame
pacing, and software/GPU fallbacks.
STATUS.md
and the plans underdocs/
track the remaining backlog for surface handles, validation, and additional platform glue. - Packaging –
dotnet pack
produces the aggregateVelloSharp
NuGet plus theVelloSharp.Native.<rid>
runtime packages (including charting, gauges, SCADA runtime, and editor core). The managed package now declares dependencies on the RID-specific native packages so consuming projects restore the correct binaries automatically. Helper scripts inscripts/
collect, copy, and repackage the native artifacts for CI and local workflows, and the CI pipeline now packs each platform (Linux, Apple, Android, WASM, Windows) in dedicated jobs before a combine step publishes the merged artifact feed consumed by the managed packaging stage.
Building the native library
Install the Rust toolchain (Rust 1.86 or newer) before building the managed projects. The VelloSharp
MSBuild project now drives cargo build
for every required native crate (accesskit_ffi
, vello_ffi
,
kurbo_ffi
, peniko_ffi
, and winit_ffi
) for the active .NET runtime identifier and configuration.
Running any of the following commands produces the native artifacts and copies them to the managed output
directory under runtimes/<rid>/native/
(and alongside the binaries for convenience):
dotnet build bindings/VelloSharp/VelloSharp.csproj
dotnet build samples/AvaloniaVelloWinitDemo/AvaloniaVelloWinitDemo.csproj
dotnet run --project samples/AvaloniaVelloWinitDemo/AvaloniaVelloWinitDemo.csproj
By default the current host target triple is used. To build for an alternate RID, pass -r <rid>
when
invoking dotnet build
or set RuntimeIdentifier
in your consuming project; make sure the corresponding
Rust target is installed (rustup target add <triple>
). The produced files are named:
RID | Triple | Artifact |
---|---|---|
win-x64 |
x86_64-pc-windows-msvc |
vello_ffi.dll |
win-arm64 |
aarch64-pc-windows-msvc |
vello_ffi.dll |
osx-x64 |
x86_64-apple-darwin |
libvello_ffi.dylib |
osx-arm64 |
aarch64-apple-darwin |
libvello_ffi.dylib |
linux-x64 |
x86_64-unknown-linux-gnu |
libvello_ffi.so |
linux-arm64 |
aarch64-unknown-linux-gnu |
libvello_ffi.so |
Note: The native crates enable the
std
feature forkurbo
/peniko
internally so the FFI layer can build against clean upstream submodules. If you invokecargo build
manually for a specific crate, pass the same feature flags (or build through theVelloSharp
project) to avoidkurbo requires the \
std` feature` errors.
Packing NuGet packages
The VelloSharp
project is now NuGet-ready. Packing requires the native artifacts for each
runtime you want to redistribute:
- Build the native libraries (e.g., via CI) and collect them under a directory layout such as
runtimes/<rid>/native/<library>
. - Set the
VelloNativeAssetsDirectory
property to that directory when invokingdotnet pack
(for example,dotnet pack bindings/VelloSharp/VelloSharp.csproj -c Release -p:VelloSkipNativeBuild=true -p:VelloNativeAssetsDirectory=$PWD/artifacts/runtimes
). - Optionally verify all runtimes by keeping the default
VelloRequireAllNativeAssets=true
, or relax the check with-p:VelloRequireAllNativeAssets=false
when experimenting locally.
The generated .nupkg
and .snupkg
files are emitted under artifacts/nuget/
.
CI publishes a managed-only VelloSharp
package by passing -p:VelloIncludeNativeAssets=false
. Native binaries are
distributed separately via the per-FFI runtime packages (VelloSharp.Native.AccessKit.*
, Kurbo
, Peniko
, Vello
,
VelloSparse
, Winit
). Applications should add whichever RIDs they need, for example:
dotnet add package VelloSharp.Native.Vello.win-x64 --prerelease
dotnet add package VelloSharp.Native.Winit.win-x64 --prerelease
Inside this repository the samples reference the Windows x64 packaging projects directly (e.g.
packaging/VelloSharp.Native.Vello/VelloSharp.Native.Vello.csproj
) so the native assets flow into bin/<TFM>/runtimes/
.
Adjust the referenced RIDs if you are developing on a different platform.
Native asset NuGet packages
Per-FFI packaging projects live under packaging/VelloSharp.Native.<Ffi>/
. Each RID-specific project wraps
the corresponding native library into a standalone NuGet package so downstream applications can pull in only the
assets they need. A typical workflow looks like this:
- Build the native crates for the desired RID(s) (
dotnet build -r osx-arm64 bindings/VelloSharp/VelloSharp.csproj
). - Run
./scripts/copy-runtimes.sh
to sync the generated artifacts into both sample outputs and eachpackaging/VelloSharp.Native.<Ffi>/runtimes/<rid>/native
directory. - Pack the runtime you care about, e.g.
dotnet pack packaging/VelloSharp.Native.Vello/VelloSharp.Native.Vello.osx-arm64.csproj
. - Reference the RID-specific packages from your application.
The packaging props also emit fallback copies (for example osx
alongside osx-arm64
) so that RID roll-forward
continues to work when .NET probes runtimes/<baseRid>/native
. The sample projects reference the Windows x64 packages so
the native binaries land in bin/<TFM>/runtimes/
without additional MSBuild logic; switch the RID suffixes if you are
developing on another platform.
Using VelloSharp
Reference the VelloSharp
project from your solution or publish it as a NuGet package.
A minimal render loop looks like:
using System.Numerics;
using VelloSharp;
using var renderer = new Renderer(width: 1024, height: 768);
using var scene = new Scene();
var path = new PathBuilder();
path.MoveTo(100, 100).LineTo(700, 200).LineTo(420, 540).Close();
scene.FillPath(path, FillRule.NonZero, Matrix3x2.Identity, RgbaColor.FromBytes(0x47, 0x91, 0xF9));
var buffer = new byte[1024 * 768 * 4];
renderer.Render(
scene,
new RenderParams(1024, 768, RgbaColor.FromBytes(0x10, 0x10, 0x12))
{
Format = RenderFormat.Bgra8,
},
buffer,
strideBytes: 1024 * 4);
buffer
now contains BGRA pixels ready for presentation via SkiaSharp, Avalonia or any other API; omit the assignment to Format
to receive RGBA output instead.
Extended bindings
The native layer now ships with optional helpers for common scene sources and GPU surfaces. All of them
round-trip through the managed API so you can mix and match with the existing Scene
primitives.
SVG scenes
VelloSvg
uses the bundled vello_svg
parser to ingest an SVG asset and append the generated scene graph to any
existing Scene
:
using var scene = new Scene();
using var svg = VelloSvg.LoadFromFile("Assets/logo.svg", scale: 1.5f);
svg.Render(scene);
// Optionally apply additional transforms or authoring on the scene afterwards.
Use LoadFromUtf8
for in-memory buffers and query the intrinsic size via the Size
property to fit your layout.
Lottie / Velato compositions
The velato
submodule provides high-quality Lottie playback. The managed
wrappers expose composition metadata and let you render into an existing Scene
or build a standalone one per
frame:
using var composition = VelatoComposition.LoadFromFile("Assets/intro_lottie.json");
using var renderer = new VelatoRenderer();
var info = composition.Info; // duration, frame rate, target size
using var scene = renderer.Render(composition, frame: 42);
// Blend multiple compositions into a shared scene
renderer.Append(scene, composition, frame: 43, alpha: 0.7);
GPU interop via wgpu
When paired with wgpu
, Vello can target swapchain textures directly. The managed side wraps the core handles so
you can drive the pipeline from your own windowing layer:
using var instance = new WgpuInstance();
var surfaceDescriptor = new SurfaceDescriptor
{
Width = width,
Height = height,
PresentMode = PresentMode.AutoVsync,
Handle = SurfaceHandle.FromWin32(hwnd), // or FromAppKit / FromWayland / FromXlib
};
using var surface = WgpuSurface.Create(instance, surfaceDescriptor);
using var adapter = instance.RequestAdapter(new WgpuRequestAdapterOptions
{
PowerPreference = WgpuPowerPreference.HighPerformance,
CompatibleSurface = surface,
});
using var device = adapter.RequestDevice(new WgpuDeviceDescriptor
{
Limits = WgpuLimitsPreset.Default,
});
using var renderer = new WgpuRenderer(device);
var surfaceTexture = surface.AcquireNextTexture();
using (var view = surfaceTexture.CreateView())
{
renderer.Render(scene, view, new RenderParams(width, height, baseColor)
{
Format = RenderFormat.Bgra8,
});
}
surfaceTexture.Present();
surfaceTexture.Dispose();
All handles are disposable and throw once released, making it easy to integrate with using
scopes. See the
Avalonia helpers below for a higher-level example.
Brushes and Layers
Scene.FillPath
and Scene.StrokePath
accept the Brush
hierarchy, enabling linear/radial gradients and image brushes in addition to solid colors. Example:
var brush = new LinearGradientBrush(
start: new Vector2(0, 0),
end: new Vector2(256, 0),
stops: new[]
{
new GradientStop(0f, RgbaColor.FromBytes(255, 0, 128)),
new GradientStop(1f, RgbaColor.FromBytes(0, 128, 255)),
});
scene.FillPath(path, FillRule.NonZero, Matrix3x2.Identity, brush);
Layer management is accessible through Scene.PushLayer
, Scene.PushLuminanceMaskLayer
, and Scene.PopLayer
, giving full control over blend modes and clip groups.
Tip: When interoperating with native paint data, wrap
PenikoBrush
handles withBrush.FromPenikoBrush
to reuse gradients or solid fills produced viapeniko_ffi
.
Geometry helpers (Kurbo)
KurboPath
, KurboAffine
, and the rest of the managed geometry types are thin wrappers over kurbo_ffi
. They
let you construct Bézier paths, apply affine transforms, and query bounds without pulling the full Rust library
into your application:
using var path = new KurboPath();
path.MoveTo(0, 0);
path.LineTo(128, 64);
path.CubicTo(256, 64, 256, 256, 128, 256);
path.Close();
var bounds = path.GetBounds();
path.ApplyAffine(KurboAffine.FromMatrix3x2(Matrix3x2.CreateRotation(MathF.PI / 4)));
var elements = path.GetElements();
These helpers surface a managed-friendly representation of the geometry used throughout Vello without introducing additional allocations in the hot path.
Images and Glyphs
Use Image.FromPixels
and Scene.DrawImage
to render textures directly. Glyph runs can be issued via Scene.DrawGlyphRun
, which takes a Font
, a glyph span, and GlyphRunOptions
for fill or stroke rendering.
Renderer Options
Renderer
exposes an optional RendererOptions
argument to select CPU-only rendering or limit the available anti-aliasing pipelines at creation time.
Windows Forms integration
VelloSharp.Windows.Core
, VelloSharp.WinForms.Core
, and VelloSharp.Integration.WinForms
bring the Vello renderer to Windows Forms.
VelloSharp.Windows.Core
centralises HWND-compatiblewgpu
device management, swapchain configuration, staging buffers, and diagnostics for Windows targets.VelloSharp.WinForms.Core
mirrors familiarSystem.Drawing
drawing types (Graphics
,Pen
,Brush
,Region
,Bitmap
,Font
,StringFormat
) on top of Vello scenes recorded throughVelloGraphics
andVelloGraphicsSession
.VelloSharp.Integration.WinForms
ships theVelloRenderControl
, sharedWindowsGpuContext
swapchain management, DPI-aware sizing, diagnostics, and automatic CPU fallbacks when the device is lost.
using VelloSharp.Windows;
using VelloSharp.WinForms;
using VelloSharp.WinForms.Integration;
var renderControl = new VelloRenderControl
{
Dock = DockStyle.Fill,
PreferredBackend = VelloRenderBackend.Gpu,
DeviceOptions = new VelloGraphicsDeviceOptions
{
Format = RenderFormat.Bgra8,
ColorSpace = WindowsColorSpace.Srgb,
},
};
renderControl.PaintSurface += (sender, e) =>
{
var scene = e.Session.Scene;
var path = new PathBuilder();
path.MoveTo(32, 32).LineTo(320, 96).LineTo(160, 240).Close();
scene.FillPath(path, FillRule.NonZero, Matrix3x2.Identity, RgbaColor.FromBytes(0x47, 0x91, 0xF9));
};
Controls.Add(renderControl);
Set PreferredBackend
to VelloRenderBackend.Cpu
for software rendering, and reuse DeviceOptions
across controls to tune swapchain format, color space, MSAA, and diagnostics. A single WindowsGpuContext
instance is shared and reference-counted so multiple controls can share the same wgpu
device safely.
samples/WinFormsMotionMarkShim
demonstrates continuous animation, backend switching, and DPI-aware resizing on top of these APIs. dotnet add package VelloSharp.Integration.WinForms
pulls in both WinForms assemblies (target net8.0-windows
with <UseWindowsForms>true</UseWindowsForms>
) and transitively restores the required native runtimes.
Avalonia integration
Avalonia support is split across four managed packages:
VelloSharp.Integration
– reusable controls, render-path helpers, and utility services shared by Avalonia and SkiaSharp hosts.VelloSharp.Avalonia.Winit
– a winit-based windowing backend that plugs into Avalonia'sIWindowingPlatform
, dispatcher, clipboard, and screen services.VelloSharp.Avalonia.Vello
– a Vello-powered rendering backend that implements Avalonia's platform render interfaces on top ofwgpu
.VelloSharp.Avalonia.Controls
– high-level Avalonia controls (canvas, animation surface, SVG presenter) built on the Vello renderer.
Opt in to the stack by extending your AppBuilder
:
AppBuilder.Configure<App>()
.UseWinit()
.UseVello()
.WithInterFont();
UseWinit
registers a single-threaded winit event loop, raw handle surfaces, and clipboard/screen implementations for Windows and macOS today, with Wayland/X11 plumbing staged next. Unsupported capabilities such as tray icons, popups, or embedded top levels currently throw NotSupportedException
so consumers can branch cleanly.
UseVello
wires Avalonia's composition pipeline to the Vello renderer. It negotiates swapchains via wgpu
, surfaces the profiler hooks, and falls back to the software VelloView
path whenever swapchain creation is denied. The renderer shares the same accesskit_ffi
bridge as the windowing layer, keeping accessibility metadata flowing into screen readers.
Managed controls
VelloSharp.Integration
includes a reusable VelloView
control that owns the renderer, scene, and
backing WriteableBitmap
. Subscribe to RenderFrame
or override OnRenderFrame
to populate the
scene — the control manages size changes, render-loop invalidation, and stride/format negotiation for you:
using VelloSharp.Integration.Avalonia;
public sealed class DemoView : VelloView
{
public DemoView()
{
RenderParameters = RenderParameters with
{
BaseColor = RgbaColor.FromBytes(18, 18, 20),
Antialiasing = AntialiasingMode.Msaa8,
};
RenderFrame += context =>
{
var scene = context.Scene;
scene.Reset();
// build your Vello scene here
};
}
}
Set IsLoopEnabled
to false
if you prefer to drive the control manually via RequestRender()
.
Surface-backed rendering (wgpu)
The Avalonia integration now drives the shared wgpu wrappers. VelloSurfaceView
tries to obtain a native
platform handle (HWND
, NSWindow
, and, in a future update, Wayland/X11). When the handle is available it creates
a WgpuInstance
, WgpuSurface
, and WgpuRenderer
, rendering directly into swapchain textures and presenting
them via wgpu
. If the platform cannot provide a compatible handle, or surface configuration fails, the control
transparently falls back to the software VelloView
path. You can continue to update the scene through
RenderFrame
without special casing either mode.
Applications that need deeper control can replicate the same sequence manually: construct a SurfaceDescriptor
from a window handle with SurfaceHandle.FromWin32
, .FromAppKit
, .FromWayland
, or .FromXlib
, configure the
surface with your preferred PresentMode
, and call WgpuRenderer.Render
with the acquired texture view. The
control exposes RendererOptions
, RenderParameters
, and IsLoopEnabled
so you can tune anti-aliasing, swapchain
formats, or frame pacing at runtime.
Platform comparison
Capability | Winit + Vello stack | Built-in Avalonia stack |
---|---|---|
Platform coverage | Windows and macOS shipping today, with X11/Wayland support staged; exposes RawWindowHandle values for swapchains. |
Win32, AppKit, X11, and Wayland backends ship with the framework today. |
Windowing features | Single dispatcher thread with one top-level window; tray icons, popups, and embedding report NotSupportedException . |
Mature support for multiple windows, popups, tray icons, and embedding scenarios. |
Rendering backend | Vello on top of wgpu (DX12, Metal, Vulkan, or GLES) with automatic fallbacks to the software path. |
Skia renderer with GPU backends (OpenGL, Vulkan, Metal, ANGLE/DirectX) and CPU fallback managed by Avalonia's compositor. |
Swapchain control | Applications choose surface formats and PresentMode via WgpuSurface descriptors. |
Swapchain setup is internal to Avalonia; apps rely on compositor defaults and the Skia backend configuration. |
GPU extensibility | Full wgpu device/queue access lets you mix custom compute or capture passes with Vello rendering. |
GPU access limited to compositor hooks; extending beyond Skia requires custom native backends. |
Accessibility | AccessKit updates flow through winit_ffi so assistive tech stays in sync. |
Platform accessibility stacks (UIA/AX/AT-SPI) driven by Avalonia's native backends. |
Samples and runtime configuration
Run the Avalonia Vello desktop samples to exercise the platform-specific hosting stacks end-to-end:
dotnet run --project samples/AvaloniaVelloWinitDemo/AvaloniaVelloWinitDemo.csproj
dotnet run --project samples/AvaloniaVelloX11Demo/AvaloniaVelloX11Demo.csproj
dotnet run --project samples/AvaloniaVelloWin32Demo/AvaloniaVelloWin32Demo.csproj
dotnet run --project samples/AvaloniaVelloNativeDemo/AvaloniaVelloNativeDemo.csproj
The Avalonia examples catalogue continues to showcase the controls on the stock platforms:
dotnet run --project samples/AvaloniaVelloExamples/AvaloniaVelloExamples.csproj
dotnet run --project samples/AvaloniaVelloControlsSample/AvaloniaVelloControlsSample.csproj
Both samples include project references to the VelloSharp.Native.*.win-x64
packaging projects. Run
scripts/pack-native-nugets
(or copy prebuilt assets into the packaging/.../runtimes
directories) before restoring so the
native DLLs land under bin/<TFM>/runtimes/
. Install the Rust toolchain only if you plan to rebuild those artifacts.
SkiaSharp shim layer
VelloSharp.Skia
provides a compatibility layer that mirrors the public API of SkiaSharp types while delegating
all rendering to the Vello engine. The shim keeps porting friction low by re-implementing familiar entry points
such as SKCanvas
, SKPaint
, SKPath
, SKImage
, and SKTypeface
on top of the managed bindings. Highlights:
- Existing SkiaSharp rendering code can be recompiled by switching
using SkiaSharp;
tousing VelloSharp.Skia;
. - The shim exposes
SKSurface.Create(VelloSurface surface)
extensions so Vello swapchains or the AvaloniaVelloSurfaceView
render directly into SkiaSharp abstractions. - Text and font services integrate with the same
parley
/skrifa
/swash
stack used by the native renderer. CallAppBuilder.UseVelloSkiaTextServices()
when bootstrapping Avalonia to replace Skia text backends with the shimmed implementations. - Recording APIs (
SKPictureRecorder
,SKPicture
) emit Vello scenes, letting you replay existing Skia display lists through the Vello renderer.
📚 A per-type comparison between the SkiaSharp APIs, their shimmed counterparts, and the underlying VelloSharp building blocks lives in
docs/skiasharp-shim-api-coverage.md
. Update that matrix alongside any new shim work.
Canvas & paint coverage
SKCanvas
now mirrors core SkiaSharp commands:SaveLayer(...)
,RestoreToCount(...)
,QuickReject(...)
, clip variants (ClipRect
,ClipRoundRect
,ClipPath
), and shape drawing helpers such asDrawLine
,DrawRect
,DrawRoundRect
,DrawOval
, andDrawPaint/DrawColor
.- Blending metadata flows through
SKPaint.BlendMode
, matching SkiaSharp’s enumeration while mapping to Vello layer blends under the hood. - Geometry helpers (
SKRoundRect
,SKRect.Empty
,SKPath.GetBounds()
) provide the data needed for interoperability with Skia-centric code bases.
ℹ️
SKClipOperation.Difference
is not yet implemented. The shim treats all clip calls asIntersect
until Vello exposes a compatible difference/composition path.
Category | Shim status | Notes |
---|---|---|
Canvas & recording (SKSurface , SKCanvas , SKPictureRecorder , SKPicture ) |
✅ Core drawing, save/restore, picture replay on Vello scenes. | Remaining work: richer blend modes, scene serialization. |
Paint & shaders (SKPaint , SKShader , gradients, blend modes) |
⚠️ Mostly implemented with Vello brushes. | Advanced Skia blend/composite modes collapse to SrcOver today. |
Raster resources (SKImage , SKBitmap , SKCodec , SKImageInfo ) |
⚠️ Decode/render via Vello FFI (PNG today). | JPEG/WebP decode and colour-space handling tracked in shim backlog. |
Geometry (SKPath , SKRoundRect , SKRect , SKMatrix ) |
✅ Path building and transforms forwarded to Vello. | Region combination helpers still pending. |
Text (SKTypeface , SKFont , SKFontManager , SKTextBlob ) |
⚠️ Glyph metrics and positioned runs powered by Vello fonts. | Font hinting/edging toggles stored but not yet honoured by renderer. |
Backend selection (SkiaBackendService , CPU/GPU adapters) |
✅ Module initializers register Vello GPU + sparse CPU pipelines. | Ensure the correct package is referenced for your target backend. |
Minimal example creating a shim surface and drawing into it:
using VelloSharp;
using VelloSharp.Skia;
var info = new SKImageInfo(512, 512, SKImageInfo.PlatformColorType, SKAlphaType.Premul);
using var surface = SKSurface.Create(info);
var canvas = surface.Canvas;
canvas.Clear(new SKColor(0x12, 0x12, 0x14));
using var paint = new SKPaint
{
Color = new SKColor(0x47, 0x91, 0xF9),
IsAntialias = true,
};
canvas.DrawCircle(256, 256, 200, paint);
using var renderer = new Renderer((uint)info.Width, (uint)info.Height);
var renderParams = new RenderParams(
(uint)info.Width,
(uint)info.Height,
RgbaColor.FromBytes(0x12, 0x12, 0x14))
{
Format = RenderFormat.Bgra8,
};
var stride = info.RowBytes;
var pixels = new byte[stride * info.Height];
renderer.Render(surface.Scene, renderParams, pixels, stride);
pixels
now contains BGRA output that you can upload to textures or pass to existing SkiaSharp consumers. For
zero-copy presentation, pair the shim with VelloSharp.Integration.Skia.SkiaRenderBridge.Render(surface, renderer, surface.Scene, renderParams)
so Vello writes straight into SKSurface
/SKBitmap
instances.
SkiaSharp interop
VelloSharp.Integration.Skia.SkiaRenderBridge
renders straight into SKBitmap
or SKSurface
instances and picks the correct render format based on the underlying color type and stride:
using SkiaSharp;
using VelloSharp.Integration.Skia;
void RenderToSurface(SKSurface surface, Renderer renderer, Scene scene, RenderParams renderParams)
{
SkiaRenderBridge.Render(surface, renderer, scene, renderParams);
surface.Canvas.Flush();
}
void RenderToBitmap(SKBitmap bitmap, Renderer renderer, Scene scene, RenderParams renderParams)
=> SkiaRenderBridge.Render(bitmap, renderer, scene, renderParams);
The helper inspects the target stride and format, and falls back to an intermediate bitmap when Skia does not expose CPU pixels for GPU-backed surfaces.
CPU/GPU render paths
For advanced scenarios you can work directly with raw buffers using
VelloSharp.Integration.Rendering.VelloRenderPath
:
Span<byte> span = GetBuffer();
var descriptor = new RenderTargetDescriptor((uint)width, (uint)height, RenderFormat.Bgra8, stride);
VelloRenderPath.Render(renderer, scene, span, renderParams, descriptor);
The descriptor validates stride and size, while Render
adjusts RenderParams
to the negotiated format
before invoking the GPU or CPU pipeline.
Automation scripts
The repository includes helper scripts that wire up the CI flow and simplify local builds. All scripts emit
artifacts under artifacts/
and are safe to combine with dotnet build
/cargo
invocations.
Native builds
scripts/build-native-macos.sh [target] [profile] [sdk] [rid]
– builds all FFI crates for macOS/iOS targets (Vello, Peniko, Kurbo, AccessKit, Winit). Pass an Apple SDK name (for examplemacosx
oriphoneos
) to compile against a specific SDK, and optionally override the runtime identifier. Defaults tox86_64-apple-darwin
inrelease
mode.scripts/build-native-linux.sh [target] [profile] [rid]
– cross-compiles the native crates for GNU/Linux platforms, defaulting tox86_64-unknown-linux-gnu
. Supplyaarch64-unknown-linux-gnu
to produce the ARM64 variant.scripts/build-native-windows.ps1 [target] [profile] [rid]
– a PowerShell helper for the Windows MSVC builds. Run from PowerShell or pwsh. Automatically maps the target triple towin-x64
/win-arm64
unless a RID is provided.scripts/build-native-android.sh [target] [profile] [rid]
– targets Android via the NDK and builds the entire FFI set. RequiresANDROID_NDK_HOME
and adds the toolchain binaries toPATH
before callingcargo
.scripts/build-native-wasm.sh [target] [profile] [rid]
– compiles the WebAssembly and static library variants for the FFI crates targetingwasm32-unknown-unknown
.
All build scripts copy the produced library into artifacts/runtimes/<rid>/native/
, making the payload immediately
available to packaging steps.
Artifact management and packaging
scripts/collect-native-artifacts.sh [source-dir] [dest-dir]
– normalises arbitrary build outputs into theruntimes/<rid>/native/
layout by scanning fornative
folders and copying their contents into the destination. Used by CI to gather per-RID outputs before packing.scripts/copy-runtimes.sh [artifacts-dir] [targets…]
/scripts/copy-runtimes.ps1 [artifactsDir] [targets…]
– copies the assembled runtime folder into project outputs and sample applications. The script defaults to propagating assets intoDebug
/Release
net8.0
builds for the library, integrations, and samples, but you can override the target projects, configurations, or frameworks viaCOPY_CONFIGURATIONS
/COPY_TARGET_FRAMEWORKS
.scripts/pack-native-nugets.sh [runtimes-dir] [output-dir]
/scripts/pack-native-nugets.ps1 [runtimesDir] [outputDir]
– iterates the collected runtimes and packs the correspondingVelloSharp.Native.<rid>
NuGet packages. Each package simply embeds thenative
folder for its RID.scripts/pack-managed-nugets.sh [output-dir] [native-feed]
/scripts/pack-managed-nugets.ps1 [nugetOutput] [nativeFeed]
– builds the managed projects inRelease
, registers a temporary NuGet source pointing at the native packages, and packs the aggregateVelloSharp
NuGet withVelloUseNativePackageDependencies=true
. Run this afterpack-native-nugets.sh
/pack-native-nugets.ps1
to produce a coherent set of packages underartifacts/nuget/
.scripts/remove-runtimes.sh [targets…]
/scripts/remove-runtimes.ps1 [targets…]
– deletes copied runtime folders from the default build outputs (or the ones supplied throughREMOVE_RUNTIMES_CONFIGURATIONS
/REMOVE_RUNTIMES_TARGET_FRAMEWORKS
), keeping local trees tidy between packaging runs.
Integration validation
scripts/run-integration-tests.sh [options]
/scripts/run-integration-tests.ps1 [-Configuration <cfg> [-Framework <tfm>] [-Platform <linux|macos|windows>] [--ManagedOnly] [--NativeOnly]]
– runs the managed and native integration projects for the requested platform (defaults to the host OS). Specify--platform
/-Platform
to override the detection,--configuration
/-Configuration
to pick Debug or Release,--framework
/-Framework
to constrain the target TFM, and--managed-only
or--native-only
to focus on a single set of projects.
Repository layout recap
ffi/vello_ffi
: Rust source for the native shared library.ffi/*_ffi
: Companion crates exposing AccessKit, Kurbo, Peniko, and Winit bindings consumed by the managed layer.VelloSharp
: C# wrapper library withScene
,Renderer
, and path-building helpers.VelloSharp.Integration
: optional Avalonia and Skia helpers with render-path negotiation utilities.samples/AvaloniaVelloWinitDemo
: Avalonia desktop sample that exercises the bindings through the AvaloniaNative/Vello path.samples/AvaloniaVelloExamples
: showcases the expanded scene catalogue on Avalonia with GPU fallback logic.samples/AvaloniaVelloControlsSample
: demonstrates the reusable VelloSharp Avalonia controls (canvas, animation, SVG).samples/AvaloniaVelloSkiaSharpSample
: end-to-end SkiaSharp shim gallery covering runtime effects, SKCodec IO, boolean geometry, and CPU/GPU backend switching atop the Vello lease pipeline.extern/vello
: upstream renderer sources (core crate, sparse strips, shaders, and examples).extern/kurbo
: geometry primitives consumed bykurbo_ffi
and Vello.extern/peniko
: brush/image utilities re-exported throughextern/peniko_shim
.extern/peniko_shim
: compatibility shim that preserves the legacypeniko
crate API surface.extern/velato
: submodule that powers the Lottie/After Effects pipeline.extern/vello_svg
: submodule responsible for SVG parsing.extern/wgpu
: vendored subset of wgpu used by the FFI for portable GPU access.extern/winit
: upstream windowing stack used by the native event-loop bridge.
License
The entire repository—including the managed bindings, native FFI crates, integrations, and samples—is distributed
under the MIT License. NuGet packages produced via dotnet pack
ship with the same MIT license text (LICENSE
) so
the published artifacts match the source tree.
To honour upstream obligations, the packages also embed the MIT/Apache-2.0 notices from the Linebender components the
FFI layer depends on (vello
, kurbo
, peniko
, wgpu
, etc.). Vendored submodules retain their original licenses—
refer to each directory for the exact terms.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- VelloSharp (>= 0.5.0-alpha.2)
- VelloSharp.Core (>= 0.5.0-alpha.2)
- VelloSharp.Text (>= 0.5.0-alpha.2)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on VelloSharp.Skia.Core:
Package | Downloads |
---|---|
VelloSharp.Skia.Gpu
Skia GPU backend bindings layered on top of VelloSharp primitives. |
|
VelloSharp.Skia.Cpu
Skia sparse CPU backend built on the shared VelloSharp Skia layer. |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last Updated |
---|---|---|
0.5.0-alpha.2 | 87 | 10/17/2025 |
0.5.0-alpha.1 | 55 | 10/11/2025 |