Skip to main content
Avalonia’s rendering system is built on a flexible, multi-backend architecture that supports multiple graphics APIs while providing a consistent programming model.

Rendering Architecture

Avalonia’s rendering pipeline consists of several layers:
  1. High-level API - Platform-agnostic drawing primitives
  2. Platform Render Interface - Abstraction over rendering backends
  3. Backend Implementations - Skia, Direct2D, or custom backends
  4. Graphics Context - OpenGL, Vulkan, Metal, or software rendering

Rendering Backends

Skia Backend (Default)

Avalonia uses SkiaSharp as its primary rendering backend. Skia is a cross-platform 2D graphics library used by Chrome, Android, and Flutter. From ~/workspace/source/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs:
public class PlatformRenderInterface : IPlatformRenderInterface
{
    public IPlatformRenderInterfaceContext CreateBackendContext(
        IPlatformGraphicsContext? graphicsContext)
    {
        if (graphicsContext == null)
            return new SkiaContext(null);
        if (graphicsContext is ISkiaGpu skiaGpu)
            return new SkiaContext(skiaGpu);
        if (graphicsContext is IGlContext gl)
            return new SkiaContext(new GlSkiaGpu(gl, maxResourceBytes));
        if (graphicsContext is IMetalDevice metal)
            return new SkiaContext(new SkiaMetalGpu(metal, maxResourceBytes));
        if (graphicsContext is IVulkanPlatformGraphicsContext vulkanContext)
            return new SkiaContext(new VulkanSkiaGpu(vulkanContext, maxResourceBytes));
    }
}

Supported Graphics APIs with Skia

  • OpenGL - Cross-platform, widely supported
  • Vulkan - High-performance, modern graphics API
  • Metal - Apple platforms (macOS, iOS)
  • Software - CPU-based fallback rendering

Configuring the Rendering Backend

using Avalonia;
using Avalonia.Skia;

AppBuilder.Configure<App>()
    .UsePlatformDetect()
    // Force software rendering
    .With(new SkiaOptions
    {
        // Disable GPU acceleration
        MaxGpuResourceSizeBytes = 0
    })
    // OR configure GPU memory limit
    .With(new SkiaOptions
    {
        MaxGpuResourceSizeBytes = 256 * 1024 * 1024 // 256 MB
    })
    .StartWithClassicDesktopLifetime(args);

Graphics Context Selection

OpenGL Backend

From ~/workspace/source/src/Avalonia.OpenGL/:
public interface IGlContext
{
    GRContext CreateBackendContext();
    IDisposable MakeCurrent();
    void SwapBuffers();
}
OpenGL versions supported:
  • OpenGL 3.2+ on Desktop
  • OpenGL ES 2.0+ on Mobile/Embedded

Vulkan Backend

Vulkan provides high-performance, low-overhead rendering:
using Avalonia.Vulkan;

// Vulkan is automatically used when available
// No explicit configuration required
Platform support:
  • Windows (via Vulkan SDK)
  • Linux (via Vulkan drivers)
  • Android (native support)
  • macOS (via MoltenVK)

Metal Backend (macOS/iOS)

Metal is automatically used on Apple platforms when available:
using Avalonia.Metal;

// Metal backend is automatically selected on macOS/iOS
// when hardware supports it

Drawing Context

The DrawingContext provides the high-level API for rendering. From ~/workspace/source/src/Skia/Avalonia.Skia/DrawingContextImpl.cs:

DrawingContext Architecture

internal partial class DrawingContextImpl : IDrawingContextImpl,
    IDrawingContextWithAcrylicLikeSupport,
    IDrawingContextImplWithEffects
{
    private readonly SKCanvas _canvas;
    private readonly Vector _intermediateSurfaceDpi;
    private readonly Stack<(SKMatrix matrix, PaintWrapper paint)> _maskStack;
    private readonly Stack<double> _opacityStack;
    private readonly Stack<RenderOptions> _renderOptionsStack;
    private readonly Stack<TextOptions> _textOptionsStack;
    private readonly GRContext? _grContext;
    private readonly ISkiaGpu? _gpu;
}

Key Rendering Features

Supported drawing operations:
  • Primitives (lines, rectangles, ellipses, paths)
  • Text rendering with advanced typography
  • Image rendering with transformations
  • Gradient fills (linear, radial, conic)
  • Brush effects (solid, gradient, image, visual)
  • Clipping and masking
  • Effects (blur, drop shadow, etc.)

Custom Drawing

using Avalonia.Media;
using Avalonia.Rendering.SceneGraph;

public class CustomControl : Control
{
    public override void Render(DrawingContext context)
    {
        base.Render(context);

        // Draw a rectangle
        var brush = new SolidColorBrush(Colors.Blue);
        var pen = new Pen(Brushes.Black, 2);
        context.DrawRectangle(brush, pen, new Rect(10, 10, 100, 50));

        // Draw an ellipse
        context.DrawEllipse(Brushes.Red, null, new Point(150, 35), 40, 25);

        // Draw text
        var formattedText = new FormattedText(
            "Hello Avalonia",
            CultureInfo.CurrentCulture,
            FlowDirection.LeftToRight,
            new Typeface(FontFamily.Default),
            16,
            Brushes.Black);
        context.DrawText(formattedText, new Point(10, 70));

        // Draw a path
        var geometry = Geometry.Parse("M 0,0 L 100,0 L 50,50 Z");
        context.DrawGeometry(Brushes.Green, pen, geometry);
    }
}

Render Loop

Avalonia uses a render loop to coordinate rendering across the application.

Render Loop Architecture

From ~/workspace/source/src/Avalonia.Base/Rendering/:
public interface IRenderLoop
{
    void Add(IRenderLoopTask task);
    void Remove(IRenderLoopTask task);
}

public interface IRenderLoopTask
{
    bool NeedsUpdate { get; }
    void Update(TimeSpan time);
    void Render();
}

Render Timing

Avalonia provides multiple render timer implementations:
  • DefaultRenderTimer - Uses platform vsync when available
  • UiThreadRenderTimer - Renders on UI thread
  • SleepLoopRenderTimer - Thread-sleep based timing
  • ThreadProxyRenderTimer - Proxies to another thread

Custom Render Loop Integration

using Avalonia.Rendering;

public class MyRenderLoopTask : IRenderLoopTask
{
    public bool NeedsUpdate { get; private set; }

    public void Update(TimeSpan time)
    {
        // Update logic before rendering
        NeedsUpdate = true;
    }

    public void Render()
    {
        // Perform rendering
        NeedsUpdate = false;
    }
}

// Register with render loop
AvaloniaLocator.Current
    .GetService<IRenderLoop>()
    .Add(myRenderLoopTask);

Rendering Optimization

Dirty Rectangle Tracking

Avalonia tracks which regions need repainting to minimize rendering overhead:
// Invalidate only changed regions
control.InvalidateVisual(); // Invalidate entire control

// Or invalidate specific region
control.InvalidateVisual(new Rect(x, y, width, height));

Layer Caching

Use render target bitmaps to cache complex rendering:
using Avalonia.Media.Imaging;

private RenderTargetBitmap? _cachedBitmap;

public void CacheRendering(Visual visual, Size size)
{
    var pixelSize = new PixelSize((int)size.Width, (int)size.Height);
    _cachedBitmap = new RenderTargetBitmap(pixelSize);
    
    using (var context = _cachedBitmap.CreateDrawingContext(null))
    {
        // Render visual to bitmap
        visual.Render(context);
    }
}

public override void Render(DrawingContext context)
{
    if (_cachedBitmap != null)
    {
        context.DrawImage(_cachedBitmap, 
            new Rect(0, 0, _cachedBitmap.PixelSize.Width, _cachedBitmap.PixelSize.Height));
    }
}
Cache rendered content when:
  • The content is complex and doesn’t change frequently
  • Rendering the same content multiple times per frame
  • The content uses expensive effects (blurs, shadows)

GPU Acceleration

Not all operations can be GPU-accelerated. The following operations may fall back to CPU rendering:
  • Very large images or surfaces
  • Complex path clipping
  • Certain blend modes
  • Custom effects requiring CPU processing

Render Transform vs. Layout Transform

<!-- RenderTransform: GPU-accelerated, no layout pass -->
<Border RenderTransform="scale(2)" />

<!-- LayoutTransform: Affects layout, triggers measure/arrange -->
<Border LayoutTransform="scale(2)" />
Use RenderTransform for:
  • Animations
  • Visual effects
  • Temporary transformations
Use LayoutTransform for:
  • Permanent transformations affecting layout
  • When child elements need to respond to transformation

Platform-Specific Rendering

Windows

  • Primary: Skia + Direct3D 11 (via ANGLE)
  • Fallback: Skia + Software

macOS

  • Primary: Skia + Metal
  • Fallback: Skia + OpenGL

Linux

  • Primary: Skia + Vulkan (when available)
  • Secondary: Skia + OpenGL
  • Fallback: Skia + Software

Mobile (iOS/Android)

  • iOS: Skia + Metal
  • Android: Skia + Vulkan or OpenGL ES

Browser (WebAssembly)

  • Primary: Skia + WebGL
  • Fallback: Skia + Software (rendered to canvas)

Advanced Rendering Topics

Pixel Format Support

From the Skia backend:
public bool IsSupportedBitmapPixelFormat(PixelFormat format) =>
    format == PixelFormats.Rgb565
    || format == PixelFormats.Bgra8888
    || format == PixelFormats.Rgba8888;
Supported formats:
  • Bgra8888 - 32-bit with premultiplied alpha (default)
  • Rgba8888 - 32-bit RGBA
  • Rgb565 - 16-bit RGB (mobile optimization)

DPI Scaling

Avalonia handles DPI scaling automatically:
// Get DPI information
var screen = control.GetVisualRoot() as Window;
if (screen != null)
{
    var scaling = screen.RenderScaling; // e.g., 1.5 for 150% DPI
}

// Create scaled render target
var dpi = new Vector(96 * scaling, 96 * scaling);
var bitmap = new RenderTargetBitmap(
    new PixelSize(width, height),
    dpi);

Render Options

Control rendering quality and performance trade-offs:
<Image RenderOptions.BitmapInterpolationMode="HighQuality"
       RenderOptions.BitmapBlendingMode="SourceOver" />

<TextBlock RenderOptions.TextRenderingMode="Antialias" />
BitmapInterpolationMode:
  • Default - Platform default
  • LowQuality - Fastest, lower quality (nearest neighbor)
  • MediumQuality - Balanced
  • HighQuality - Slowest, best quality (bicubic)
TextRenderingMode:
  • Antialias - Grayscale antialiasing
  • SubpixelAntialias - RGB subpixel antialiasing (default)
  • Alias - No antialiasing

Debugging Rendering

Renderer Diagnostics

using Avalonia.Rendering;

// Enable renderer debug overlays
RendererDiagnostics.DebugOverlays = RendererDebugOverlays.Fps 
                                  | RendererDebugOverlays.LayoutTimeGraph
                                  | RendererDebugOverlays.RenderTimeGraph;

Available Debug Overlays:

  • Fps - Frames per second counter
  • LayoutTimeGraph - Layout pass timing
  • RenderTimeGraph - Render pass timing
  • DirtyRects - Shows invalidated regions

See Also

Build docs developers (and LLMs) love