From e8d60deaf5f0d6e3c2690b4c25cb9f82d4425d3d Mon Sep 17 00:00:00 2001
From: Luke <55367595+luke-whos-here@users.noreply.github.com>
Date: Mon, 15 Jun 2026 16:21:40 +0100
Subject: [PATCH 1/8] General style edits
---
docs/app-development/performance.md | 120 +++++++++++++---------------
1 file changed, 55 insertions(+), 65 deletions(-)
diff --git a/docs/app-development/performance.md b/docs/app-development/performance.md
index 0e3573119..905643d5e 100644
--- a/docs/app-development/performance.md
+++ b/docs/app-development/performance.md
@@ -9,7 +9,7 @@ This guide covers common performance considerations for Avalonia applications an
## UI virtualization
-When displaying large collections, virtualization ensures only visible items are created and rendered. Avalonia's `ListBox`, `TreeView`, `DataGrid`, and `ItemsRepeater` support virtualization by default.
+When displaying large collections, virtualization ensures only visible items are created and rendered. Some controls support virtualization by default, such as [`ListBox`](/controls/data-display/collections/listbox) or [`ItemsRepeater`](/controls/data-display/collections/itemsrepeater).
### How virtualization works
@@ -17,27 +17,27 @@ Instead of creating a control for every item in the collection, the virtualizing
### Ensuring virtualization is active
-Virtualization requires a constrained height. If the items control is inside a `StackPanel` or another control that gives it infinite height, virtualization is disabled:
+Virtualization requires a constrained height. If the item is inside a control that gives it infinite height, virtualization is disabled.
```xml
-
+
-
+
-
+
```
-### ItemsRepeater for custom layouts
+### `ItemsRepeater` for custom layouts
`ItemsRepeater` provides a lower-level virtualizing control for custom layouts:
@@ -58,7 +58,7 @@ Virtualization requires a constrained height. If the items control is inside a `
### Buffer factor for smooth scrolling
-`VirtualizingStackPanel` supports a `BufferFactor` property that keeps additional items realized beyond the visible viewport. This reduces recycling frequency during scrolling, which can eliminate stutter caused by garbage collection, particularly on mobile devices.
+`VirtualizingStackPanel` supports a `BufferFactor` property that keeps additional items from realizing beyond the visible viewport. This reduces recycling frequency during scrolling, which can eliminate stutter, particularly on mobile devices.
```xml
@@ -70,21 +70,21 @@ Virtualization requires a constrained height. If the items control is inside a `
```
-A `BufferFactor` of `1` realizes items across one extra viewport height above and below the visible area. The default is `0` (no buffer). Higher values use more memory but produce smoother scrolling for complex item templates.
+A `BufferFactor` of `1` realizes items across one extra viewport height above and below the visible area. The default is `0` (no buffer). Higher values use more memory but produce smoother scrolling.
### Variable-height items
-`VirtualizingStackPanel` works best when all items have the same height. When items have variable heights, the panel must estimate total scroll extent based on measured items, which can cause scroll bar jumps and layout recalculations. If your items vary significantly in height, consider these strategies:
+`VirtualizingStackPanel` is optimized for collections where all items have the same height. The panel estimates scroll extent based on number of items, meaning collections containing items with variable heights can cause scroll bar jumps and layout recalculations. If your items vary significantly in height, consider these strategies:
-- **Use a uniform estimated height.** Give all items a fixed `Height` or `MinHeight` so the virtualizing panel can calculate scroll extent accurately. Allow content to clip or scroll internally if it exceeds the estimated size.
-- **Flatten hierarchical data.** Instead of nesting expanders inside a virtualizing list, flatten the tree into a single list with indent levels. This lets the virtualizing panel manage all rows directly. `TreeView` uses this approach internally.
+- **Use a uniform height.** Give all items a fixed `Height` or `MinHeight` so the virtualizing panel can calculate scroll extent accurately. Allow content to clip or scroll internally if it exceeds the estimated size.
+- **Flatten hierarchical data.** Instead of nesting expanders inside a virtualizing list, flatten the tree into a single list with indent levels. This lets the virtualizing panel manage rows directly. `TreeView` uses this approach internally.
- **Limit realized items.** If virtualization is not feasible (for example, a complex property grid with expanders), limit how many controls exist at once. Load only the visible section and create additional items on demand as the user expands or scrolls.
-### Reduce control template complexity
+### Reducing control template complexity
-Complex controls like [`TextBox`](/api/avalonia/controls/textbox) contain a deep visual tree (borders, scroll viewers, watermark layers). When you create thousands of them, template instantiation and measurement dominate startup time.
+Complex controls like [`TextBox`](/controls/input/text-input/textbox) contain a deep visual tree with borders, scroll viewers and watermark layers. When you create many of them, template instantiation and measurement dominate startup time.
-**Use lightweight controls for display, swap on interaction.** Show values with `TextBlock` (which has a minimal visual tree) and replace with a `TextBox` only when the user clicks to edit:
+**Use lightweight controls for display and swap on interaction.** For example, you can show values with `TextBlock` (which has a minimal visual tree) and replace it with a `TextBox` only when the user clicks to edit:
```csharp
// In your DataTemplate code-behind or custom control
@@ -103,7 +103,7 @@ display.PointerPressed += (s, e) =>
};
```
-**Re-template heavy controls.** If you must use `TextBox` everywhere, create a simplified control theme that removes unnecessary visual elements (watermark, clear button, scroll viewer) to reduce the visual tree depth:
+**Re-template heavy controls.** If you must use `TextBox` everywhere, create a simplified control theme that removes unnecessary visual elements (e.g., watermark, clear button, scroll viewer) to reduce the visual tree depth:
```xml
@@ -127,9 +127,9 @@ Apply it to controls that do not need the full feature set:
```
-## Layout performance
+## Layout optimization
-### Avoid deep nesting
+### Avoiding deep nesting
Each level of nesting adds measure and arrange passes. Flatten your layout where possible:
@@ -151,7 +151,7 @@ Each level of nesting adds measure and arrange passes. Flatten your layout where
```
-### Use Grid instead of nested StackPanels
+### Replacing nested stack panels with grids
A single `Grid` with rows and columns is more efficient than multiple nested `StackPanel` controls:
@@ -165,9 +165,9 @@ A single `Grid` with rows and columns is more efficient than multiple nested `St
```
-### Minimize InvalidateArrange / InvalidateMeasure
+### Minimizing `InvalidateArrange` and `InvalidateMeasure`
-Property changes that affect layout (e.g., Width, Height, Margin, Padding) trigger layout recalculations. Batch property changes when possible:
+Property changes that affect layout (e.g., `Width`, `Height`, `Margin`, `Padding`) trigger layout recalculations. Batch property changes when possible:
```csharp
// Set multiple properties together; Avalonia batches layout
@@ -178,9 +178,9 @@ myControl2.Height = 200;
## Rendering performance
-### Hide unused controls with IsVisible
+### Hiding unused controls with `IsVisible`
-Setting `IsVisible="False"` completely removes a control from both layout and rendering. The layout system skips the measure and arrange passes for that control and its entire subtree, and the renderer does not draw it. This makes `IsVisible` an effective way to reduce work for conditionally shown content:
+Setting `IsVisible="False"` removes a control from both layout and rendering. The layout system skips the measure and arrange passes for that control and its entire subtree, and the renderer does not draw it. This makes `IsVisible` an effective way to reduce work for conditionally shown content:
```xml
@@ -192,15 +192,17 @@ Setting `IsVisible="False"` completely removes a control from both layout and re
If you need to hide a control visually while keeping its layout space reserved, use `Opacity="0"` instead. An element with `Opacity="0"` still participates in layout and can receive input.
-### Use ClipToBounds judiciously
+### Using `ClipToBounds` judiciously
`ClipToBounds="True"` creates a clip layer. Only use it when child content actually exceeds the control bounds.
-### Reduce hit-testing cost
+### Reducing hit-testing cost
-When a pointer event occurs, Avalonia walks the visual tree and tests each element. With hundreds or thousands of children in a `Canvas` or `Panel`, this linear walk adds a noticeable delay between clicking and receiving the event. Set `IsHitTestVisible="False"` on elements that do not need pointer interaction, and consider an overlay-based hit-test strategy or custom rendering for scenes with many objects. See [Hit Testing: Performance with many elements](/docs/graphics-animation/hit-testing#performance-with-many-elements) for patterns and code examples.
+When a pointer event occurs, Avalonia walks the visual tree and tests each element. This linear walk can cause a noticeable delay between clicking and receiving the event if a control contains many children.
-Transparent elements also participate in hit testing. If a control does not need pointer interaction, set `IsHitTestVisible="False"`:
+Set `IsHitTestVisible="False"` on elements that do not need pointer interaction. Consider an overlay-based hit-test strategy or custom rendering for scenes with many objects. See [Hit Testing: Performance with many elements](/docs/graphics-animation/hit-testing#performance-with-many-elements) for patterns and code examples.
+
+Transparent elements also participate in hit testing. If a transparent control does not need pointer interaction, set `IsHitTestVisible="False"` to exclude it from hit-testing.
```xml
@@ -208,13 +210,13 @@ Transparent elements also participate in hit testing. If a control does not need
```
-### Reduce visual complexity
+### Reducing visual complexity
-- Minimize the number of `BoxShadow` effects (each shadow adds a render pass)
-- Avoid overlapping semi-transparent elements
-- Use `Opacity` on a parent element rather than on each child individually
+- Minimize the number of `BoxShadow` effects, which add an individual render pass each.
+- Avoid overlapping semi-transparent elements.
+- Use `Opacity` on a parent element rather than on each child,
-### BitmapCache
+### Bitmap cache
For visuals that are expensive to render but change infrequently, use `BitmapCache` to rasterize them to a bitmap surface. The control and its children are rendered once into an intermediate bitmap, and that bitmap is reused for subsequent frames until the content changes.
@@ -227,15 +229,15 @@ For visuals that are expensive to render but change infrequently, use `BitmapCac
```
-`BitmapCache` properties:
+ #### `BitmapCache` properties
| Property | Type | Default | Description |
|---|---|---|---|
-| `RenderAtScale` | `double` | `1` | Resolution multiplier for the cached bitmap. Values above 1 increase quality (useful for content that will be scaled up), values below 1 reduce memory at the cost of quality. Set to 0 to disable caching. |
+| `RenderAtScale` | `double` | `1` | Resolution multiplier for the cached bitmap. Values above 1 increase quality. Values below 1 reduce memory at the cost of quality. Value equal to 0 disables caching. |
| `SnapsToDevicePixels` | `bool` | `false` | Aligns the cached bitmap to device pixel boundaries for sharper text and line rendering. |
-| `EnableClearType` | `bool` | `false` | Enables ClearType subpixel text rendering within the cached surface. Without this, text in the cache uses grayscale antialiasing. |
+| `EnableClearType` | `bool` | `false` | Enables `ClearType` subpixel text rendering within the cached surface. Without this, text in the cache uses grayscale antialiasing. |
-For best results with text-heavy cached content, enable both `SnapsToDevicePixels` and `EnableClearType`:
+For text-heavy content, it is recommended to cache with `SnapsToDevicePixels` and `EnableClearType` enabled.
```xml
@@ -246,7 +248,7 @@ For best results with text-heavy cached content, enable both `SnapsToDevicePixel
```
-### BitmapInterpolationMode
+### Bitmap interpolation mode
For images that do not need high-quality scaling, use a lower interpolation mode:
@@ -257,9 +259,9 @@ For images that do not need high-quality scaling, use a lower interpolation mode
### GPU resource cache size
-Avalonia uses Skia with GPU acceleration by default. Skia maintains a GPU resource cache for textures and other GPU-backed surfaces. The default cache limit is approximately 28 MB. If your app works with large images, tilesets, or many cached visuals, images that exceed the cache limit are re-uploaded to the GPU each frame, causing stuttering.
+Avalonia uses Skia with GPU acceleration by default. Skia maintains a GPU resource cache for textures and other GPU-backed surfaces. The default cache limit is approximately 28 MB. If your app works with large images, tilesets, or many cached visuals, images that exceed the cache limit are re-uploaded to the GPU each frame, which can cause stuttering.
-Increase the cache by configuring `SkiaOptions` at startup:
+Increase the cache limit by configuring `SkiaOptions` at startup:
```csharp
AppBuilder.Configure()
@@ -274,23 +276,11 @@ Choose a value appropriate for your target hardware. Most integrated GPUs have a
## Data binding performance
-### Use compiled bindings
-
-Compiled bindings resolve property paths at compile time, avoiding runtime reflection:
-
-```xml
-
-
-
-```
-
-Or enable project-wide in `.csproj`:
+### Compiled bindings
-```xml
-true
-```
+Compiled bindings resolve property paths at compile time, avoiding runtime reflection. They are [enabled by default from Avalonia version 12](/docs/avalonia12-breaking-changes#compiled-bindings-are-enabled-by-default).
-### Avoid unnecessary bindings
+### Avoiding unnecessary bindings
Use static values instead of bindings for properties that never change:
@@ -303,7 +293,7 @@ Use static values instead of bindings for properties that never change:
```
-### Use OneTime bindings for static data
+### Using one-time bindings for static data
If a value is set once and never changes, use `OneTime` mode to avoid ongoing change tracking:
@@ -311,13 +301,13 @@ If a value is set once and never changes, use `OneTime` mode to avoid ongoing ch
```
-## Collection performance
+## Collections
-### Use ObservableCollection for small-to-medium lists
+### Using `ObservableCollection` for small-to-medium lists
`ObservableCollection` notifies the UI of individual item additions and removals efficiently.
-### Batch large updates
+### Batching large updates
When adding many items at once, consider replacing the collection rather than adding items one by one:
@@ -333,7 +323,7 @@ OnPropertyChanged(nameof(Items));
### Incremental loading
-When you must create many controls without virtualization (for example, a property grid or inspector panel), adding them all at once blocks the UI thread during measurement. Instead, add items in batches and yield to the dispatcher between each batch so the UI remains responsive:
+If you must create many controls without virtualization (for example, a property grid or inspector panel), adding them all at once blocks the UI thread during measurement. Instead, add items in batches and yield to the dispatcher between each batch so the UI remains responsive:
```csharp
private async Task LoadItemsIncrementally(IList items, Panel container)
@@ -354,15 +344,15 @@ private async Task LoadItemsIncrementally(IList items, Panel cont
}
```
-Choose a batch size large enough to fill the visible area on the first pass. This lets the user see content immediately while remaining items load progressively.
+Choose a batch size large enough to fill the visible area on the first pass. This lets the user see content immediately, while the remaining items load progressively.
-### Use DynamicData for large reactive collections
+### Using `DynamicData` for large reactive collections
For collections with frequent sorting, filtering, or complex transformations, [DynamicData](https://github.com/reactivemarbles/DynamicData) provides optimized reactive pipelines that minimize UI updates.
## Async and threading
-### Keep the UI thread free
+### Keeping the UI thread free
Move heavy computation to background threads:
@@ -371,7 +361,7 @@ var data = await Task.Run(() => LoadLargeDataSet());
Items = new ObservableCollection- (data);
```
-### Debounce rapid input
+### Debouncing rapid input
For search-as-you-type scenarios, debounce the input to avoid running expensive operations on every keystroke:
@@ -381,9 +371,9 @@ this.WhenAnyValue(x => x.SearchText)
.Subscribe(text => ApplyFilter(text));
```
-### Use DispatcherPriority.Background for deferred work
+### Using `DispatcherPriority.Background` for deferred work
-Schedule low-priority updates that run when the UI thread is idle:
+Schedule low-priority updates to run when the UI thread is idle:
```csharp
Dispatcher.UIThread.Post(() =>
@@ -405,7 +395,7 @@ JetBrains profiling tools work with Avalonia applications. Use them to identify
### Diagnostic overlays
-Enable the FPS overlay in your `App.axaml.cs`:
+Enable the FPS overlay in `App.axaml.cs`:
```csharp
public override void OnFrameworkInitializationCompleted()
From 04be4a8a732a10cdb9b5ac496badd1d3d53ae3e8 Mon Sep 17 00:00:00 2001
From: Luke <55367595+luke-whos-here@users.noreply.github.com>
Date: Mon, 15 Jun 2026 16:41:57 +0100
Subject: [PATCH 2/8] Add new section to performance guide on region clipping
---
docs/app-development/performance.md | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/docs/app-development/performance.md b/docs/app-development/performance.md
index 905643d5e..94a99f0bc 100644
--- a/docs/app-development/performance.md
+++ b/docs/app-development/performance.md
@@ -274,6 +274,25 @@ AppBuilder.Configure()
Choose a value appropriate for your target hardware. Most integrated GPUs have at least 2 GB of shared memory, so values of 256 MB or 512 MB are safe for desktop apps. Mobile devices may require lower values.
+### Region dirty rect clipping
+
+When content changes, Avalonia repaints the affected, or "dirty", regions of the screen rather than the whole frame. [`CompositionOptions.UseRegionDirtyRectClipping`](/api/avalonia/rendering/composition/compositionoptions) tracks those regions more precisely using a dirty rect system, but adds additional CPU time to process the render pass.
+
+This option is **disabled by default** from Avalonia 12.1 to minimize loss of frame rate in complex scenes.
+
+To enable region clipping, you must explicitly set `UseRegionDirtyRectClipping = true` in `CompositionOptions` at startup. Enabling this option can be useful on some target platforms without GPU acceleration, such as embedded or software-rendered devices, where reducing the painted area matters more than the clipping cost.
+
+```csharp
+AppBuilder.Configure()
+ .UsePlatformDetect()
+ .With(new CompositionOptions
+ {
+ UseRegionDirtyRectClipping = true
+ });
+```
+
+When region clipping is enabled, `MaxDirtyRects` caps how many dirty rects are tracked per frame. The default is `8`. Setting it to zero or a negative value bypasses Avalonia's tracking and uses the underlying drawing context's region support directly.
+
## Data binding performance
### Compiled bindings
From 0a4beeaefb3255a9392c6df44f199de5e16474d2 Mon Sep 17 00:00:00 2001
From: Luke <55367595+luke-whos-here@users.noreply.github.com>
Date: Mon, 15 Jun 2026 16:53:17 +0100
Subject: [PATCH 3/8] Add region dirty rect clipping to embedded Linux guide
Update the embedded Linux page with a new section explaining the benefits of dirty rect clipping and how to enable it.
---
.../embedded-linux/embedded-linux.md | 25 +++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/docs/platform-specific-guides/embedded-linux/embedded-linux.md b/docs/platform-specific-guides/embedded-linux/embedded-linux.md
index 4e790605e..bd40f8736 100644
--- a/docs/platform-specific-guides/embedded-linux/embedded-linux.md
+++ b/docs/platform-specific-guides/embedded-linux/embedded-linux.md
@@ -164,6 +164,30 @@ Touch input coordinates are automatically adjusted to match the configured orien
Rotation uses an offscreen framebuffer and an OpenGL shader to transform the image. There is no performance cost when `Rotation0` is used.
:::
+## Rendering performance
+
+Embedded devices often render in software through the framebuffer, or use GPUs that are weaker than a desktop's. On this kind of hardware, the cost of painting pixels dominates each frame, so reducing the screen area Avalonia repaints has a larger impact than on a desktop GPU.
+
+### Enabling region dirty rect clipping
+
+[`CompositionOptions.UseRegionDirtyRectClipping`](/api/avalonia/rendering/composition/compositionoptions) more precisely tracks regions using a dirty rect system. This shrinks the area to be repainted, at the cost of some CPU work to compute the clip.
+
+This option is **disabled by default** from Avalonia 12.1, because on a fast GPU the extra clipping work outweighs the saved overdraw. Embedded Linux is the case it benefits: with a weaker GPU, the reduction in painted pixels outweighs the clipping cost.
+
+To enable region clipping, you must explicitly set `UseRegionDirtyRectClipping = true` in `CompositionOptions` at startup.
+
+```csharp
+public static AppBuilder BuildAvaloniaApp()
+ => AppBuilder.Configure()
+ .UsePlatformDetect()
+ .With(new CompositionOptions
+ {
+ UseRegionDirtyRectClipping = true
+ });
+```
+
+When region clipping is enabled, `MaxDirtyRects` caps how many dirty rects are tracked per frame. See [Region dirty rect clipping](/docs/app-development/performance#region-dirty-rect-clipping) in the performance optimization guide for more information.
+
## Verifying your DRM setup
Before running an Avalonia application, you can verify that DRM is working with `kmscube`:
@@ -187,3 +211,4 @@ For applications that need an on-screen keyboard (kiosks, point-of-sale systems,
- [Virtual Keyboard](/docs/platform-specific-guides/embedded-linux/virtual-keyboard) for on-screen keyboard support
- [Deploying to Embedded Linux](/docs/deployment/embedded-linux)
- [Desktop Linux](/docs/platform-specific-guides/linux) for X11 and Wayland environments
+- [Performance optimization](/docs/app-development/performance) for rendering, layout, and binding tuning
From f44376df6c44313fb118554983ddfeb0e6434ee4 Mon Sep 17 00:00:00 2001
From: Luke <55367595+luke-whos-here@users.noreply.github.com>
Date: Mon, 15 Jun 2026 16:54:56 +0100
Subject: [PATCH 4/8] Add crosslink to embedded linux page
---
docs/app-development/performance.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/app-development/performance.md b/docs/app-development/performance.md
index 94a99f0bc..4b8a0ce27 100644
--- a/docs/app-development/performance.md
+++ b/docs/app-development/performance.md
@@ -280,7 +280,7 @@ When content changes, Avalonia repaints the affected, or "dirty", regions of the
This option is **disabled by default** from Avalonia 12.1 to minimize loss of frame rate in complex scenes.
-To enable region clipping, you must explicitly set `UseRegionDirtyRectClipping = true` in `CompositionOptions` at startup. Enabling this option can be useful on some target platforms without GPU acceleration, such as embedded or software-rendered devices, where reducing the painted area matters more than the clipping cost.
+To enable region clipping, you must explicitly set `UseRegionDirtyRectClipping = true` in `CompositionOptions` at startup. Enabling this option can be useful on some target platforms without GPU acceleration, such as [embedded](/docs/platform-specific-guides/embedded-linux/embedded-linux) or software-rendered devices, where reducing the painted area matters more than the clipping cost.
```csharp
AppBuilder.Configure()
From 6b0677a6cda4138b41b861f4353ce7a7c249d5b5 Mon Sep 17 00:00:00 2001
From: Luke <55367595+luke-whos-here@users.noreply.github.com>
Date: Mon, 15 Jun 2026 17:01:44 +0100
Subject: [PATCH 5/8] Address linter findings
---
docs/app-development/performance.md | 2 +-
.../platform-specific-guides/embedded-linux/embedded-linux.md | 4 +++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/docs/app-development/performance.md b/docs/app-development/performance.md
index 4b8a0ce27..f39da6524 100644
--- a/docs/app-development/performance.md
+++ b/docs/app-development/performance.md
@@ -276,7 +276,7 @@ Choose a value appropriate for your target hardware. Most integrated GPUs have a
### Region dirty rect clipping
-When content changes, Avalonia repaints the affected, or "dirty", regions of the screen rather than the whole frame. [`CompositionOptions.UseRegionDirtyRectClipping`](/api/avalonia/rendering/composition/compositionoptions) tracks those regions more precisely using a dirty rect system, but adds additional CPU time to process the render pass.
+When content changes, Avalonia repaints the affected, or "dirty", regions of the screen rather than the whole frame. [`CompositionOptions.UseRegionDirtyRectClipping`](/api/avalonia/rendering/composition/compositionoptions) tracks those regions more precisely using a dirty rect system, but adds extra CPU time to process the render pass.
This option is **disabled by default** from Avalonia 12.1 to minimize loss of frame rate in complex scenes.
diff --git a/docs/platform-specific-guides/embedded-linux/embedded-linux.md b/docs/platform-specific-guides/embedded-linux/embedded-linux.md
index bd40f8736..65d4e5cd8 100644
--- a/docs/platform-specific-guides/embedded-linux/embedded-linux.md
+++ b/docs/platform-specific-guides/embedded-linux/embedded-linux.md
@@ -1,6 +1,8 @@
---
id: embedded-linux
title: Embedded Linux
+description: Run Avalonia on embedded Linux devices using the framebuffer or DRM/KMS, with display scaling, screen rotation, and touch input.
+doc-type: how-to
---
Avalonia supports running on embedded Linux devices without a desktop environment. This includes single-board computers like the Raspberry Pi, industrial panels, kiosks, and point-of-sale terminals. Instead of connecting through a windowing system like X11, Avalonia renders directly to the display hardware using either the Linux framebuffer or the Direct Rendering Manager (DRM).
@@ -172,7 +174,7 @@ Embedded devices often render in software through the framebuffer, or use GPUs t
[`CompositionOptions.UseRegionDirtyRectClipping`](/api/avalonia/rendering/composition/compositionoptions) more precisely tracks regions using a dirty rect system. This shrinks the area to be repainted, at the cost of some CPU work to compute the clip.
-This option is **disabled by default** from Avalonia 12.1, because on a fast GPU the extra clipping work outweighs the saved overdraw. Embedded Linux is the case it benefits: with a weaker GPU, the reduction in painted pixels outweighs the clipping cost.
+This option is **disabled by default** from Avalonia 12.1, because on a fast GPU the extra clipping work outweighs the saved overdraw. Embedded Linux is one case where it helps: with a weaker GPU, the reduction in painted pixels outweighs the clipping cost.
To enable region clipping, you must explicitly set `UseRegionDirtyRectClipping = true` in `CompositionOptions` at startup.
From ff96391c182d7baf2755b92694c6f5f8f1534487 Mon Sep 17 00:00:00 2001
From: Luke <55367595+luke-whos-here@users.noreply.github.com>
Date: Mon, 15 Jun 2026 17:05:46 +0100
Subject: [PATCH 6/8] Tweak code sample for consistency
---
.../embedded-linux/embedded-linux.md | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/docs/platform-specific-guides/embedded-linux/embedded-linux.md b/docs/platform-specific-guides/embedded-linux/embedded-linux.md
index 65d4e5cd8..924f7a816 100644
--- a/docs/platform-specific-guides/embedded-linux/embedded-linux.md
+++ b/docs/platform-specific-guides/embedded-linux/embedded-linux.md
@@ -179,13 +179,12 @@ This option is **disabled by default** from Avalonia 12.1, because on a fast GPU
To enable region clipping, you must explicitly set `UseRegionDirtyRectClipping = true` in `CompositionOptions` at startup.
```csharp
-public static AppBuilder BuildAvaloniaApp()
- => AppBuilder.Configure()
- .UsePlatformDetect()
- .With(new CompositionOptions
- {
- UseRegionDirtyRectClipping = true
- });
+AppBuilder.Configure()
+ .UsePlatformDetect()
+ .With(new CompositionOptions
+ {
+ UseRegionDirtyRectClipping = true
+ });
```
When region clipping is enabled, `MaxDirtyRects` caps how many dirty rects are tracked per frame. See [Region dirty rect clipping](/docs/app-development/performance#region-dirty-rect-clipping) in the performance optimization guide for more information.
From 3fec5111c053f045f6f6ecf30a72cdfdfe26f053 Mon Sep 17 00:00:00 2001
From: Luke <55367595+luke-whos-here@users.noreply.github.com>
Date: Mon, 15 Jun 2026 17:52:10 +0100
Subject: [PATCH 7/8] Address Copilot review feedback
---
docs/app-development/performance.md | 12 ++++++------
.../embedded-linux/embedded-linux.md | 4 ++--
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/docs/app-development/performance.md b/docs/app-development/performance.md
index f39da6524..823417991 100644
--- a/docs/app-development/performance.md
+++ b/docs/app-development/performance.md
@@ -58,7 +58,7 @@ Virtualization requires a constrained height. If the item is inside a control th
### Buffer factor for smooth scrolling
-`VirtualizingStackPanel` supports a `BufferFactor` property that keeps additional items from realizing beyond the visible viewport. This reduces recycling frequency during scrolling, which can eliminate stutter, particularly on mobile devices.
+`VirtualizingStackPanel` supports a `BufferFactor` property that keeps additional items beyond the visible viewport in a realized state. This reduces recycling frequency during scrolling, which can eliminate stutter, particularly on mobile devices.
```xml
@@ -214,7 +214,7 @@ Transparent elements also participate in hit testing. If a transparent control d
- Minimize the number of `BoxShadow` effects, which add an individual render pass each.
- Avoid overlapping semi-transparent elements.
-- Use `Opacity` on a parent element rather than on each child,
+- Use `Opacity` on a parent element rather than on each child.
### Bitmap cache
@@ -233,7 +233,7 @@ For visuals that are expensive to render but change infrequently, use `BitmapCac
| Property | Type | Default | Description |
|---|---|---|---|
-| `RenderAtScale` | `double` | `1` | Resolution multiplier for the cached bitmap. Values above 1 increase quality. Values below 1 reduce memory at the cost of quality. Value equal to 0 disables caching. |
+| `RenderAtScale` | `double` | `1` | Resolution multiplier for the cached bitmap. Values above 1 increase quality. Values below 1 reduce memory at the cost of quality. A value of 0 disables caching. |
| `SnapsToDevicePixels` | `bool` | `false` | Aligns the cached bitmap to device pixel boundaries for sharper text and line rendering. |
| `EnableClearType` | `bool` | `false` | Enables `ClearType` subpixel text rendering within the cached surface. Without this, text in the cache uses grayscale antialiasing. |
@@ -276,11 +276,11 @@ Choose a value appropriate for your target hardware. Most integrated GPUs have a
### Region dirty rect clipping
-When content changes, Avalonia repaints the affected, or "dirty", regions of the screen rather than the whole frame. [`CompositionOptions.UseRegionDirtyRectClipping`](/api/avalonia/rendering/composition/compositionoptions) tracks those regions more precisely using a dirty rect system, but adds extra CPU time to process the render pass.
+When content changes, Avalonia repaints the affected (or "dirty") regions of the screen rather than the whole frame. [`CompositionOptions.UseRegionDirtyRectClipping`](/api/avalonia/rendering/composition/compositionoptions) enables more accurate dirty-rect tracking by utilizing regions, but adds extra CPU time to process the render pass.
-This option is **disabled by default** from Avalonia 12.1 to minimize loss of frame rate in complex scenes.
+This option is **disabled by default** starting with Avalonia 12.1 to minimize loss of frame rate in complex scenes.
-To enable region clipping, you must explicitly set `UseRegionDirtyRectClipping = true` in `CompositionOptions` at startup. Enabling this option can be useful on some target platforms without GPU acceleration, such as [embedded](/docs/platform-specific-guides/embedded-linux/embedded-linux) or software-rendered devices, where reducing the painted area matters more than the clipping cost.
+To enable region clipping, you must explicitly set `UseRegionDirtyRectClipping = true` in `CompositionOptions` at startup. Enabling this option can be useful on some target platforms without GPU acceleration, such as [embedded Linux](/docs/platform-specific-guides/embedded-linux/embedded-linux) or other software-rendered devices, where reducing the painted area matters more than the clipping cost.
```csharp
AppBuilder.Configure()
diff --git a/docs/platform-specific-guides/embedded-linux/embedded-linux.md b/docs/platform-specific-guides/embedded-linux/embedded-linux.md
index 924f7a816..d97cc289f 100644
--- a/docs/platform-specific-guides/embedded-linux/embedded-linux.md
+++ b/docs/platform-specific-guides/embedded-linux/embedded-linux.md
@@ -172,9 +172,9 @@ Embedded devices often render in software through the framebuffer, or use GPUs t
### Enabling region dirty rect clipping
-[`CompositionOptions.UseRegionDirtyRectClipping`](/api/avalonia/rendering/composition/compositionoptions) more precisely tracks regions using a dirty rect system. This shrinks the area to be repainted, at the cost of some CPU work to compute the clip.
+[`CompositionOptions.UseRegionDirtyRectClipping`](/api/avalonia/rendering/composition/compositionoptions) enables more accurate dirty-rect tracking by utilizing regions. This shrinks the area to be repainted, at the cost of some CPU work to compute the clip.
-This option is **disabled by default** from Avalonia 12.1, because on a fast GPU the extra clipping work outweighs the saved overdraw. Embedded Linux is one case where it helps: with a weaker GPU, the reduction in painted pixels outweighs the clipping cost.
+This option is **disabled by default** starting with Avalonia 12.1, because on a fast GPU the extra clipping work outweighs the saved overdraw. Embedded Linux is one case where it helps: with a weaker GPU, the reduction in painted pixels outweighs the clipping cost.
To enable region clipping, you must explicitly set `UseRegionDirtyRectClipping = true` in `CompositionOptions` at startup.
From 2cebc0ef1302571358a83352efe0e12d6f192f39 Mon Sep 17 00:00:00 2001
From: Luke <55367595+luke-whos-here@users.noreply.github.com>
Date: Mon, 15 Jun 2026 17:57:03 +0100
Subject: [PATCH 8/8] Address review feedback
---
docs/app-development/performance.md | 2 +-
docs/platform-specific-guides/embedded-linux/embedded-linux.md | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/app-development/performance.md b/docs/app-development/performance.md
index 823417991..28e2276fc 100644
--- a/docs/app-development/performance.md
+++ b/docs/app-development/performance.md
@@ -278,7 +278,7 @@ Choose a value appropriate for your target hardware. Most integrated GPUs have a
When content changes, Avalonia repaints the affected (or "dirty") regions of the screen rather than the whole frame. [`CompositionOptions.UseRegionDirtyRectClipping`](/api/avalonia/rendering/composition/compositionoptions) enables more accurate dirty-rect tracking by utilizing regions, but adds extra CPU time to process the render pass.
-This option is **disabled by default** starting with Avalonia 12.1 to minimize loss of frame rate in complex scenes.
+This option is **disabled by default** starting with Avalonia 12.1 to minimize loss of frame rate.
To enable region clipping, you must explicitly set `UseRegionDirtyRectClipping = true` in `CompositionOptions` at startup. Enabling this option can be useful on some target platforms without GPU acceleration, such as [embedded Linux](/docs/platform-specific-guides/embedded-linux/embedded-linux) or other software-rendered devices, where reducing the painted area matters more than the clipping cost.
diff --git a/docs/platform-specific-guides/embedded-linux/embedded-linux.md b/docs/platform-specific-guides/embedded-linux/embedded-linux.md
index d97cc289f..28faef44b 100644
--- a/docs/platform-specific-guides/embedded-linux/embedded-linux.md
+++ b/docs/platform-specific-guides/embedded-linux/embedded-linux.md
@@ -174,7 +174,7 @@ Embedded devices often render in software through the framebuffer, or use GPUs t
[`CompositionOptions.UseRegionDirtyRectClipping`](/api/avalonia/rendering/composition/compositionoptions) enables more accurate dirty-rect tracking by utilizing regions. This shrinks the area to be repainted, at the cost of some CPU work to compute the clip.
-This option is **disabled by default** starting with Avalonia 12.1, because on a fast GPU the extra clipping work outweighs the saved overdraw. Embedded Linux is one case where it helps: with a weaker GPU, the reduction in painted pixels outweighs the clipping cost.
+This option is **disabled by default** starting with Avalonia 12.1, because on a fast GPU the extra clipping work outweighs the saved overdraw. Embedded Linux is one case where it might help: with a weaker GPU, the reduction in painted pixels may outweigh the clipping cost.
To enable region clipping, you must explicitly set `UseRegionDirtyRectClipping = true` in `CompositionOptions` at startup.