Skip to content

Add Avalonia 11/12 ProGPU rendering integration#36

Merged
wieslawsoltes merged 23 commits into
mainfrom
feature/avalonia-progpu-integration
Jul 24, 2026
Merged

Add Avalonia 11/12 ProGPU rendering integration#36
wieslawsoltes merged 23 commits into
mainfrom
feature/avalonia-progpu-integration

Conversation

@wieslawsoltes

@wieslawsoltes wieslawsoltes commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Summary

This pull request moves the Avalonia ProGPU integration out of the Avalonia
source tree and into ProGPU as a standalone, packageable integration lane.

It includes:

  • a ProGPU renderer for Avalonia 12.0.5;
  • a Silk.NET windowing and input backend for Avalonia 12.0.5;
  • thin Avalonia 11.3.18 projects that compile the same shared implementation
    with narrowly scoped AVALONIA11 conditionals;
  • the original Avalonia 12.0.5 Skia backend built unchanged against ProGPU's
    SkiaSharp compatibility implementation;
  • standalone ControlCatalog, RenderDemo, and ProGpuSandbox applications;
  • focused renderer, Silk.NET, Skia-compatibility, and baseline tests;
  • bounded path-atlas uploads and direct contained rounded-border rendering;
  • context-portable immutable bitmap images and Retina resize validation for the
    Skia compatibility path;
  • separate NuGet packaging lanes for Avalonia 11 and Avalonia 12;
  • an isolated package-only consumer used to verify both supported Avalonia
    versions.

The Avalonia fork is a pinned submodule rather than copied source. Each
source-linked project contains a PORTING-NOTICE.txt that records its source
repository, original path, tag, exact source commit, and the small set of local
overrides.

Motivation

The ProGPU Avalonia renderer and Silk.NET backend previously lived in an
Avalonia feature branch, which coupled development and validation to the
Avalonia monorepo. Avalonia 11 compatibility also required a second
implementation lane.

This change makes ProGPU the owner of the integration while keeping a single
shared renderer and platform-backend implementation. Applications can consume
the integration through ordinary packages, and both supported Avalonia
versions can be validated without building the Avalonia source tree as a
project graph; the pinned checkout supplies linked source only.

Source provenance

The port is based on these immutable Avalonia revisions:

  • wieslawsoltes/Avalonia, tag progpu-avalonia-v12.0.5-preview.19,
    commit
    5378af03f17a4d9d2845882229ffed7f67350037;
  • AvaloniaUI/Avalonia, tag 12.0.5, commit
    fee9c561ce036e8a3e8cee2397c75ca599b4790d, for the effective unchanged
    src/Skia/Avalonia.Skia source set.

external/Avalonia pins the fork tag
progpu-avalonia-v12.0.5-preview.19 at
5378af03f17a4d9d2845882229ffed7f67350037. The Skia shim, ControlCatalog,
and RenderDemo source-link their unchanged implementation, XAML, and resources
from that checkout. Only one Skia file, two ControlCatalog files, and fifteen
RenderDemo files remain locally as explicit overrides.

The Avalonia Skia adapter includes the upstream license and a detailed source
record. The fork tag changed GlyphRunImpl.cs, so the local override restores
the original Avalonia 12.0.5 file. A dedicated integrity test substitutes that
override and checks the effective 54-file set against the fixed upstream
SHA-256 digest.

Renderer and platform integration

Avalonia 12

ProGPU.Avalonia.Rendering implements Avalonia's platform render interface on
top of the local ProGPU Backend, Vector, Text, Compute, Scene, and SkiaSharp
projects. It includes geometry, drawing-context, bitmap, glyph, text-shaping,
tile-brush, cache, render-target, and API-lease integration.

ProGPU.Avalonia.SilkNet provides the desktop window, screen, cursor,
clipboard, dispatcher, input mapping, icon, render-timer, and framebuffer
implementation. Window framebuffers use physical framebuffer dimensions while
Avalonia continues to operate in logical coordinates.

Avalonia 11

The Avalonia 11 renderer and Silk.NET projects contain only project
configuration and source-link the Avalonia 12 implementation directories.
They define AVALONIA11 for the small number of API differences and pin the
Avalonia dependency to 11.3.18.

This avoids maintaining divergent copies while preserving version-specific
package identities:

  • ProGPU.Avalonia.Rendering 12.0.5-preview.26;
  • ProGPU.Avalonia.SilkNet 12.0.5-preview.26;
  • ProGPU.Avalonia.Rendering 11.3.18-preview.26;
  • ProGPU.Avalonia.SilkNet 11.3.18-preview.26.

Avalonia Skia compatibility

The previous out-of-tree Skia modifications were removed. The
ProGPU.Avalonia.SkiaShim project now source-links the effective
byte-identical Avalonia 12.0.5 Skia implementation against ProGPU's local
SkiaSharp project.

ProGPU-specific presentation is implemented below the Avalonia source:

  • GpuFramebufferPresentationRegistry associates a CPU framebuffer address
    with a typed GPU presenter;
  • GpuTextureSurfacePresenter blits the rendered ProGPU texture directly to
    the acquired WebGPU surface texture;
  • SKSurface registers CPU-backed surfaces and can present the GPU texture
    without performing a live-surface CPU readback;
  • the Silk.NET locked framebuffer invokes the registered presenter when the
    original Avalonia framebuffer backend completes the frame.

The direct ProGPU rendering path does not request the framebuffer address, so
it does not allocate the compatibility CPU buffer.

Bitmap-backed immutable SKImage instances retain one tightly packed RGBA
snapshot and lazily materialize one GPU texture per target WgpuContext.
Subsequent draws reuse that context-local texture; GPU-only and borrowed images
still reject cross-context use. Silk paint callbacks now push the exact
window-owned context, and window disposal releases that same instance. This
fixes the resize-time cross-context exception without modifying the effective
Avalonia Skia sources or adding a GPU readback.

Path rendering and atlas validation

The ControlCatalog follow-up fixes both the WebGPU copy validation error and
the malformed title-bar border:

  • path rasters that remain larger than the maximum atlas after growth are
    rejected before placement or upload;
  • coverage uploads independently validate the destination texture range and
    source staging-buffer range before recording a WebGPU command;
  • contained canonical rounded-rectangle differences preserve their exact
    contours with even-odd fill instead of using the general GPU boolean solver;
  • partial rounded borders use the bounded direct triangle-SDF path, avoiding
    the page-width atlas allocation that caused the original error;
  • a canonical sharp rectangle expressed with three explicit edges plus its
    implicit closing edge uses the direct two-triangle path only when it cannot
    fit the maximum atlas; smaller rectangles keep their existing atlas
    antialiasing;
  • the original TransitioningContentControl transition-masked path remains
    unchanged after direct comparison with Avalonia main on the native Skia
    backend confirmed the same three-contour silhouette.

Focused regressions cover oversized single rasters, both copy-range guards,
exact elliptical rounded-rectangle differences, the transition icon's two
implicitly closed fill contours, and the partial rounded title border with a
zero-width bottom edge. They also cover the oversized canonical-rectangle
fallback, the unchanged atlas path for a fitting rectangle, and explicit
failure for an oversized arbitrary path.

Release before/after measurements compared commit b682d0cd directly with
its parent over four alternating processes per revision:

  • unchanged compiled-scene replay remained stable at 0.0287 ms versus
    0.0254 ms median, with all frames hitting the scene cache;
  • invalidated ordinary paths remained stable at 1.4235 ms versus 1.4051 ms
    median and showed no material allocation change;
  • changing rounded-border differences improved from 15.3218 ms to 1.4791 ms
    median frame time, while compilation fell from 6.8087 ms to 0.2068 ms and
    managed allocation fell by 72.7%;
  • the broader Release Vector Shapes benchmark showed no compositor or
    compilation regression.

A separate Release image benchmark compared the parent revision with the final
source over four processes per case. The unchanged same-context path measured
1.4852 ms/frame before and 1.4796 ms/frame after (-0.4%, within noise), with a
23-byte/frame allocation difference. Cross-context materialization cost
17.8708 ms once; cached cross-context draws measured 1.5415 ms/frame and 8,718
managed bytes/frame, confirming there is no per-frame CPU upload.

Samples

The following applications and support projects are standalone projects while
their unchanged sample sources are linked from the pinned Avalonia submodule:

  • ControlCatalog and ControlCatalog.Desktop;
  • MiniMvvm and SampleControls;
  • RenderDemo;
  • ProGpuSandbox.

ControlCatalog, RenderDemo, and ProGpuSandbox use UseSilkNet().UseProGpu() by
default. ControlCatalog and RenderDemo can also exercise the unchanged Avalonia
Skia backend over ProGPU's SkiaSharp compatibility layer.

Packaging

The integration has a dedicated package manifest and pack/publish scripts
because the Avalonia 11 and Avalonia 12 projects share package IDs while
publishing different exact versions.

The repository package audit now classifies:

  • 30 runtime package projects;
  • 4 Avalonia integration-lane projects;
  • 13 non-shipping projects.

The isolated integration/ProGpuPackageApp consumer restores only from package
feeds and contains no project references. Its runner supports both Avalonia
12.0.5 and Avalonia 11.3.18 through explicit version properties and isolated
NuGet configuration/cache directories.

Tests and validation

Validation performed on the final source state:

  • full src/ProGPU.slnx build succeeded;
  • all 2,375 ProGPU runtime tests passed;
  • all 177 focused compositor, path-atlas, path-operation, and arc compiler
    regressions passed;
  • 57 focused ProGPU Avalonia renderer tests passed;
  • 34 focused Silk.NET dispatcher, input, cursor, icon, timer, and framebuffer
    tests passed;
  • the render-baseline inventory test passed;
  • both Avalonia Skia compatibility and source-integrity tests passed;
  • all 274 expected render baselines and 10 input images decoded successfully;
  • all four integration packages and symbol packages were produced;
  • package archive inspection confirmed exact Avalonia and ProGPU dependencies;
  • isolated package-only builds succeeded for Avalonia 12.0.5 and Avalonia
    11.3.18;
  • ControlCatalog remained active with direct ProGPU rendering without WebGPU
    validation errors; the title border rendered without the former diagonal
    fill;
  • ControlCatalog also remained active with --skiashim;
  • an automated --skiashim Retina resize sequence covering 1280x760,
    1420x900, 1210x680, and 1360x820 completed without cross-context,
    oversized-path, or WebGPU validation errors;
  • RenderDemo and ProGpuSandbox remained active until intentionally stopped;
  • package-manifest verification and script syntax checks passed.

The full solution currently reports known warnings from Avalonia private API
usage and pre-existing dependency advisories/conflicts; it completes with no
errors.

Rendering research

The implementation includes a research record comparing the integration
against Skia/SkParagraph, DirectWrite/Direct2D and Win2D, WebRender,
Vello/Parley, and HarfBuzz. It records the decisions around lazy
initialization, shaped-text reuse, retained scenes, cache ownership, culling
and upload, physical framebuffer sizing, subpixel positioning, font fallback,
and device-loss handling.

@wieslawsoltes
wieslawsoltes marked this pull request as ready for review July 24, 2026 13:45
@wieslawsoltes
wieslawsoltes merged commit 54a1797 into main Jul 24, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant