Performance Optimization
Reducing startup time with ReadyToRun
XPF applications can benefit significantly from ReadyToRun (R2R) compilation, which pre-compiles assemblies to native code. WPF libraries shipped by Microsoft are normally pre-compiled as R2R, but XPF libraries are not by default.
Enable ReadyToRun in your .csproj:
<PropertyGroup>
<PublishReadyToRun>true</PublishReadyToRun>
</PropertyGroup>
Then publish with a runtime identifier:
dotnet publish -r linux-x64 -c Release
This can reduce application startup time substantially, particularly on Linux embedded devices.
On Linux, ReadyToRun may change how native .so libraries are resolved. See Linux: Native Library Resolution for details.
Rendering performance
Configuring Skia and composition options
XPF uses Skia as its rendering engine. You can tune rendering performance through SkiaOptions and CompositionOptions in a custom initialization:
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Skia;
using AvaloniaUI.Xpf;
AppBuilder.Configure<AvaloniaUI.Xpf.Helpers.DefaultXpfAvaloniaApplication>()
.UsePlatformDetect()
.With(new SkiaOptions
{
MaxGpuResourceSizeBytes = 512 * 1024 * 1024 // 512 MB GPU resource cache
})
.With(new CompositionOptions
{
UseRegionDirtyRectClipping = true
})
.WithAvaloniaXpf()
.SetupWithLifetime(new ClassicDesktopStyleApplicationLifetime
{
ShutdownMode = ShutdownMode.OnExplicitShutdown
});
MaxGpuResourceSizeBytes: Increases the GPU texture cache, reducing re-uploads for applications with many visual elements.UseRegionDirtyRectClipping: Limits rendering to only the regions of the screen that have changed, improving performance for partial updates.
Blur effects
Blur effects (BlurEffect, DropShadowEffect with blur) are computationally expensive in Skia. A complex UI with blur enabled can reduce the framerate from 60fps to 30fps or lower. If rendering performance is a concern:
- Remove or reduce blur radii where possible
- Consider using solid color backgrounds instead of acrylic/blur effects
- Test on your target hardware early
Dynamic XAML loading
XamlReader.Load parses and instantiates XAML at runtime. For large XAML documents, this can block the UI thread for several seconds. This is a fundamental limitation shared with WPF.
Strategies for improving dynamic XAML performance:
- Precompile XAML into assemblies: If the XAML content is known at build time, compile it into a separate assembly and load the assembly dynamically at runtime. Compiled XAML (BAML) loads significantly faster than raw XAML parsing.
- Break up large XAML: Split large XAML documents into smaller pieces and load them incrementally.
- Load on a background thread: Parse the XAML string on a background thread, then instantiate the resulting object tree on the UI thread.
BAML (compiled XAML) provides the best loading performance, but there is no supported public API for creating loose BAML files. Compile XAML into assemblies instead.
Embedding high-performance content
For performance-critical rendering (such as real-time meters, audio visualizations, or 3D content), consider embedding Avalonia controls in your XPF application using AvaloniaHost. Avalonia's CompositionCustomVisuals API allows rendering directly on the composition thread, bypassing the WPF dispatcher entirely.
For OpenGL content, see the OpenGL sample which demonstrates embedding OpenGL rendering within an XPF window using ICompositionGpuInterop.