Skip to content

Add Graphite presentation interop - #4729

Draft
mattleibow wants to merge 1 commit into
mainfrom
mattleibow-graphite-interop-bindings
Draft

Add Graphite presentation interop#4729
mattleibow wants to merge 1 commit into
mainfrom
mattleibow-graphite-interop-bindings

Conversation

@mattleibow

Copy link
Copy Markdown
Contributor

Description

Adds the Graphite APIs required for on-screen presentation without adding any view implementation. Vulkan presentation needs acquisition waits, render-complete signals, a transition to VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, and completion callbacks; the existing binding only supported offscreen recording.

This layer also exposes deferred canvases for independent thread-affine recorders, a 64-bit-safe Vulkan image overload for 32-bit Android, and backend texture metadata. Native views and MAUI are intentionally split into follow-up PRs.

Related issues

Related to #4721
Related to #3962

Required skia PR

Requires mono/skia#345

Areas affected

  • Managed API (binding/)
  • Native / C API (externals/skia/src/c, include/c)
  • Generated P/Invoke bindings
  • Native dependency or Skia update (libpng, HarfBuzz, FreeType, zlib, milestone bump, …)
  • Views & integrations (MAUI, Uno, WPF, WinUI, Blazor, …)
  • Rendering output / visual behavior
  • Performance
  • Tests
  • Build, packaging, or CI
  • Documentation or samples

Changes

Public API

public delegate void SKGraphiteFinishedDelegate(bool success);

public class SKGraphiteBackendSemaphore : SKObject
{
    public static SKGraphiteBackendSemaphore CreateVulkan(ulong vkSemaphore);
}

public class SKGraphiteMutableTextureState : SKObject
{
    public static SKGraphiteMutableTextureState CreateVulkan(int imageLayout, uint queueFamilyIndex);
}

public ref struct SKGraphiteInsertRecordingOptions;

public static SKGraphiteBackendTexture CreateVulkan(
    int width, int height, SKGraphiteVkTextureInfo info,
    int imageLayout, uint queueFamilyIndex, ulong vkImage);
public SKGraphiteTextureInfo SKGraphiteBackendTexture.TextureInfo { get; }
public SKCanvas SKGraphiteRecorder.CreateDeferredCanvas(
    SKImageInfo info, SKGraphiteTextureInfo textureInfo);
public SKGraphiteInsertStatus SKGraphiteContext.InsertRecording(
    SKGraphiteRecording recording, SKGraphiteInsertRecordingOptions options);

Behavior

The fallback Vulkan allocator is internally synchronized so multiple Graphite recorders can allocate concurrently. Invalid target-state and deferred-canvas inputs are rejected before entering unsafe native paths.

Testing

  • dotnet build binding/SkiaSharp/SkiaSharp.csproj -f net10.0
  • API validation tests pass.
  • Vulkan console project passes under the existing macOS backend policy (4 passed, 23 skipped).
  • The companion native PR was previously built from source across Android and Apple; view/runtime validation remains in the follow-up PRs.

Checklist

  • Tests added or updated (if omitted, explain why above)
  • Changes above lists all public API and behavioral changes (or "None.")
  • New/changed public API? Filed Document Graphite native and MAUI views SkiaSharp-API-docs#200 so reference docs can be written later
  • Native change? Companion mono/skia PR linked above and bindings regenerated

Expose deferred canvases, Vulkan synchronization and texture-state primitives, and 64-bit-safe external handles independently of any view implementation.\n\nCo-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>\nCopilot-Session: 00cda8ff-9603-406f-ae2e-45c70e39b3e7
@github-actions

Copy link
Copy Markdown
Contributor

📦 Try the packages from this PR

Warning

Do not run these scripts without first reviewing the code in this PR.

Step 1 — Download the packages

bash / macOS / Linux:

curl -fsSL https://raw.githubusercontent.com/mono/SkiaSharp/main/scripts/get-skiasharp-pr.sh | bash -s -- 4729

PowerShell / Windows:

iex "& { $(irm https://raw.githubusercontent.com/mono/SkiaSharp/main/scripts/get-skiasharp-pr.ps1) } 4729"

Step 2 — Add the local NuGet source

dotnet nuget add source ~/.skiasharp/hives/pr-4729/packages --name skiasharp-pr-4729
More options
Option Description
--successful-only / -SuccessfulOnly Only use successful builds
--force / -Force Overwrite previously downloaded packages
--list / -List List available artifacts without downloading
--build-id ID / -BuildId ID Download from a specific build

Or download manually from Azure Pipelines — look for the nuget artifact on the build for this PR.

Remove the source when you're done:

dotnet nuget remove source skiasharp-pr-4729

@github-actions

Copy link
Copy Markdown
Contributor

📖 Documentation Preview

The documentation for this PR has been deployed and is available at:

🔗 View Staging Site
🔗 View Staging Docs
🔗 View Staging Gallery (Blazor)
🔗 View Staging Gallery (Uno Platform)
🔗 View Staging SkiaFiddle

This preview will be updated automatically when you push new commits to this PR.


This comment is automatically updated by the documentation staging workflow.

@github-actions

Copy link
Copy Markdown
Contributor

📊 SkiaSharp benchmarks — PR #4729

this PR (full source build) vs 🌙 nightly · Linux · Windows · macOS

Informational only — this never blocks the PR. 🟢 faster / less allocation · 🔴 slower / more allocation; moves under 5% are hidden as noise.

⏱️ Times are raw BenchmarkDotNet means, and the ⭐ PR and baseline legs run on separate CI runners, so microbenchmarks can swing run-to-run — treat small time deltas as noise. Allocations are deterministic and the reliable signal. The interactive perf-dashboard (linked below) applies smoothing for the trend view.

Highlights

⏱️ Time — 🔴 53 slower · 🟢 27 faster

  • 🔴 RuntimeEffectShaderBenchmark.DrawFrame · Linux · 2.85 ms → 4.86 ms (+71%)
  • 🔴 SceneRenderBenchmark.RenderFrame(Complexity: 4) · Linux · 18.07 ms → 26.54 ms (+47%)
  • 🔴 SceneRenderBenchmark.RenderFrame(Complexity: 1) · Linux · 3.94 ms → 5.73 ms (+46%)
  • 🔴 RasterImageLifecycleBenchmark.CreateDataWithReleaseProc(Count: 256) · Windows · 96.45 µs → 134.18 µs (+39%)
  • 🟢 ColorMathBenchmark.ToColor(Colors: 4096) · Linux · 14.99 µs → 9.24 µs (-38%)
  • …and 75 more (see details below)

📦 Allocations — 🔴 1 more alloc · 🟢 0 less alloc

  • 🔴 RuntimeEffectShaderBenchmark.DrawFrame · Linux · 683 B → 730 B (+7%)
Full per-OS benchmark deltas

Linux

⏱️ Time (vs 🌙 nightly 4.152.0-nightly.10)

Benchmark baseline this PR Δ
RuntimeEffectShaderBenchmark.DrawFrame 2.85 ms 4.86 ms 🔴 +71%
SceneRenderBenchmark.RenderFrame(Complexity: 4) 18.07 ms 26.54 ms 🔴 +47%
SceneRenderBenchmark.RenderFrame(Complexity: 1) 3.94 ms 5.73 ms 🔴 +46%
ColorMathBenchmark.ToColor(Colors: 4096) 14.99 µs 9.24 µs 🟢 -38%
ColorMathBenchmark.UnPreMultiply(Colors: 4096) 11.44 µs 7.84 µs 🟢 -31%
ColorMathBenchmark.PreMultiply(Colors: 4096) 12.87 µs 8.99 µs 🟢 -30%
ColorParseBenchmark.Parse(Iterations: 1000) 74.14 µs 58.28 µs 🟢 -21%
MatrixOpsBenchmark.Invert(Count: 4096) 130.80 µs 103.36 µs 🟢 -21%
LargeImageScaleBenchmark.UpscaleOpaque(Size: 2048) 2.92 ms 2.31 ms 🟢 -21%
MatrixMapPointsBenchmark.MapPoint(Points: 256) 4.51 µs 3.63 µs 🟢 -19%
MatrixMapPointsBenchmark.MapPoint(Points: 4096) 71.97 µs 58.08 µs 🟢 -19%
LargeImageScaleBenchmark.UpscaleOpaque(Size: 1024) 757.90 µs 612.73 µs 🟢 -19%
MatrixOpsBenchmark.Concat(Count: 4096) 218.29 µs 183.84 µs 🟢 -16%
PathBoundsBenchmark.TightBounds(Points: 1024) 10.15 µs 8.65 µs 🟢 -15%
RasterImageLifecycleBenchmark.CreateRasterImage(Count: 256) 257.65 µs 221.78 µs 🟢 -14%
LargeImageScaleBenchmark.UpscaleCrossfade(Size: 2048) 7.96 ms 7.10 ms 🟢 -11%
MatrixMapPointsBenchmark.MapVector(Points: 4096) 174.32 µs 155.62 µs 🟢 -11%
MatrixMapPointsBenchmark.MapRadius(Points: 256) 13.72 µs 12.26 µs 🟢 -11%
PathBoundsBenchmark.TightBounds(Points: 64) 977.7 ns 873.8 ns 🟢 -11%
LargeImageScaleBenchmark.UpscaleCrossfade(Size: 1024) 2.06 ms 1.85 ms 🟢 -10%
CanvasDrawBenchmark.Draw(Shapes: 64) 4.15 ms 4.57 ms 🔴 +10%
MatrixMapPointsBenchmark.MapVector(Points: 256) 10.84 µs 9.75 µs 🟢 -10%
CanvasDrawBenchmark.Draw(Shapes: 512) 33.17 ms 36.48 ms 🔴 +10%
MatrixMapPointsBenchmark.MapRadius(Points: 4096) 216.94 µs 197.26 µs 🟢 -9%
BitmapDrawBenchmark.DrawScaledTiles(Tiles: 256) 1.33 ms 1.21 ms 🟢 -9%
…and 4 more

📦 Allocations (vs 🌙 nightly 4.152.0-nightly.10)

Benchmark baseline this PR Δ
RuntimeEffectShaderBenchmark.DrawFrame 683 B 730 B 🔴 +7%

Windows

⏱️ Time (vs 🌙 nightly 4.152.0-nightly.10)

Benchmark baseline this PR Δ
RasterImageLifecycleBenchmark.CreateDataWithReleaseProc(Count: 256) 96.45 µs 134.18 µs 🔴 +39%
ColorMathBenchmark.ToColor(Colors: 4096) 11.93 µs 16.14 µs 🔴 +35%
RasterImageLifecycleBenchmark.CreateRasterImage(Count: 256) 238.66 µs 319.97 µs 🔴 +34%
PathBoundsBenchmark.TightBounds(Points: 1024) 16.70 µs 21.46 µs 🔴 +28%
PathBoundsBenchmark.TightBounds(Points: 64) 1.61 µs 2.02 µs 🔴 +25%
MatrixMapPointsBenchmark.MapRadius(Points: 4096) 153.16 µs 179.34 µs 🔴 +17%
MatrixMapPointsBenchmark.MapRadius(Points: 256) 9.81 µs 11.25 µs 🔴 +15%
CanvasDrawBenchmark.Draw(Shapes: 512) 20.57 ms 23.21 ms 🔴 +13%
BitmapDrawBenchmark.DrawScaledTiles(Tiles: 256) 1.34 ms 1.50 ms 🔴 +12%
ColorParseBenchmark.Parse(Iterations: 1000) 77.81 µs 86.14 µs 🔴 +11%
MatrixMapPointsBenchmark.MapPoints(Points: 256) 182.7 ns 201.8 ns 🔴 +10%
MatrixMapPointsBenchmark.MapRect(Points: 4096) 128.91 µs 140.95 µs 🔴 +9%
CanvasDrawBenchmark.Draw(Shapes: 64) 2.65 ms 2.89 ms 🔴 +9%
BitmapDrawBenchmark.DrawScaledTiles(Tiles: 64) 361.89 µs 392.73 µs 🔴 +9%
MatrixOpsBenchmark.Concat(Count: 4096) 256.01 µs 276.24 µs 🔴 +8%
MatrixMapPointsBenchmark.MapVector(Points: 4096) 137.55 µs 148.35 µs 🔴 +8%
MatrixMapPointsBenchmark.MapPoints(Points: 4096) 2.10 µs 2.26 µs 🔴 +8%
MatrixMapPointsBenchmark.MapVector(Points: 256) 8.88 µs 9.38 µs 🔴 +6%
RuntimeEffectShaderBenchmark.DrawFrame 1.22 ms 1.28 ms 🔴 +5%
SceneRenderBenchmark.RenderFrame(Complexity: 4) 10.38 ms 10.91 ms 🔴 +5%
MatrixOpsBenchmark.Invert(Count: 4096) 148.24 µs 155.78 µs 🔴 +5%

macOS

⏱️ Time (vs 🌙 nightly 4.152.0-nightly.10)

Benchmark baseline this PR Δ
MatrixMapPointsBenchmark.MapPoint(Points: 4096) 18.14 µs 25.04 µs 🔴 +38%
MatrixMapPointsBenchmark.MapPoints(Points: 4096) 1.52 µs 2.05 µs 🔴 +35%
RasterImageLifecycleBenchmark.CreateDataWithReleaseProc(Count: 256) 66.42 µs 88.17 µs 🔴 +33%
PathBoundsBenchmark.TightBounds(Points: 1024) 8.07 µs 10.70 µs 🔴 +33%
RuntimeEffectShaderBenchmark.DrawFrame 507.38 µs 637.01 µs 🔴 +26%
LargeImageScaleBenchmark.UpscaleCrossfade(Size: 1024) 1.45 ms 1.74 ms 🔴 +20%
BitmapDrawBenchmark.DrawUnscaledTiles(Tiles: 64) 148.63 µs 176.91 µs 🔴 +19%
ColorParseBenchmark.Parse(Iterations: 1000) 63.10 µs 74.84 µs 🔴 +19%
RasterImageLifecycleBenchmark.CreateRasterImage(Count: 256) 141.56 µs 166.19 µs 🔴 +17%
MatrixMapPointsBenchmark.MapPoints(Points: 256) 135.9 ns 157.8 ns 🔴 +16%
BitmapDrawBenchmark.DrawScaledTiles(Tiles: 64) 195.71 µs 222.36 µs 🔴 +14%
PathBoundsBenchmark.TightBounds(Points: 64) 850.3 ns 954.9 ns 🔴 +12%
MatrixMapPointsBenchmark.MapRect(Points: 4096) 49.43 µs 55.50 µs 🔴 +12%
BitmapDrawBenchmark.DrawUnscaledTiles(Tiles: 256) 543.43 µs 607.33 µs 🔴 +12%
MatrixMapPointsBenchmark.MapRadius(Points: 256) 6.17 µs 6.82 µs 🔴 +10%
MatrixOpsBenchmark.Invert(Count: 4096) 65.06 µs 58.59 µs 🟢 -10%
SceneRenderBenchmark.RenderFrame(Complexity: 1) 1.18 ms 1.29 ms 🔴 +10%
SceneRenderBenchmark.RenderFrame(Complexity: 4) 5.40 ms 5.91 ms 🔴 +9%
LargeImageScaleBenchmark.UpscaleOpaque(Size: 2048) 2.69 ms 2.44 ms 🟢 -9%
BitmapDrawBenchmark.DrawScaledTiles(Tiles: 256) 664.73 µs 722.90 µs 🔴 +9%
ColorMathBenchmark.ToColorF(Colors: 4096) 4.92 µs 5.32 µs 🔴 +8%
MatrixMapPointsBenchmark.MapRadius(Points: 4096) 97.96 µs 105.70 µs 🔴 +8%
ColorMathBenchmark.ToColor(Colors: 4096) 18.93 µs 17.46 µs 🟢 -8%
MatrixMapPointsBenchmark.MapPoint(Points: 256) 1.14 µs 1.22 µs 🔴 +7%
MatrixOpsBenchmark.Concat(Count: 4096) 111.66 µs 119.03 µs 🔴 +7%
…and 5 more

📈 Full interactive perf-dashboard & run details →

@github-actions

Copy link
Copy Markdown
Contributor

📦 Artifact size report

Packages from this PR (build 1548149) vs the latest nightly baseline 4.152.0-nightly.17 (observed 2026-08-11).

Total .nupkg size: 569.8 MB → 569.6 MB (−265.6 KB, -0.0%)

Packages

⚠️ marks growth over 500.0 KB or 2%. Changes under 50.0 KB are treated as noise.

Package baseline this PR Δ Δ%
SkiaSharp.NativeAssets.WinUI 109.1 MB 108.5 MB 🟢 −694.1 KB -0.6%
SkiaSharp 9.1 MB 9.2 MB 🔴 +105.1 KB +1.1%
SkiaSharp.NativeAssets.WebAssembly 69.7 MB 69.7 MB 🔴 +94.1 KB +0.1%
SkiaSharp.NativeAssets.Win32 85.7 MB 85.8 MB 🔴 +65.5 KB +0.1%

+36 package(s) unchanged (< 50.0 KB).

Per-file changes

SkiaSharp

File Size
lib/net462/SkiaSharp.dll 862.0 KB → 872.0 KB (🔴 +10.0 KB)
lib/net48/SkiaSharp.dll 862.0 KB → 871.5 KB (🔴 +9.5 KB)
lib/net10.0-android36.0/SkiaSharp.dll 534.0 KB → 540.5 KB (🔴 +6.5 KB)
lib/net10.0-ios26.0/SkiaSharp.dll 536.5 KB → 543.0 KB (🔴 +6.5 KB)
lib/net10.0-maccatalyst26.0/SkiaSharp.dll 536.5 KB → 543.0 KB (🔴 +6.5 KB)
lib/net10.0-tvos26.0/SkiaSharp.dll 536.5 KB → 543.0 KB (🔴 +6.5 KB)
lib/net6.0/SkiaSharp.dll 510.0 KB → 516.5 KB (🔴 +6.5 KB)
lib/net9.0-android35.0/SkiaSharp.dll 534.0 KB → 540.5 KB (🔴 +6.5 KB)
lib/net9.0-ios18.0/SkiaSharp.dll 536.5 KB → 543.0 KB (🔴 +6.5 KB)
lib/net9.0-maccatalyst18.0/SkiaSharp.dll 536.5 KB → 543.0 KB (🔴 +6.5 KB)
lib/net9.0-tvos18.0/SkiaSharp.dll 536.5 KB → 543.0 KB (🔴 +6.5 KB)
lib/netstandard2.1/SkiaSharp.dll 514.0 KB → 520.5 KB (🔴 +6.5 KB)
lib/net10.0-macos26.0/SkiaSharp.dll 536.5 KB → 542.5 KB (🔴 +6.0 KB)
lib/net10.0-tizen10.0/SkiaSharp.dll 554.0 KB → 560.0 KB (🔴 +6.0 KB)
lib/net10.0-windows10.0.19041/SkiaSharp.dll 539.0 KB → 545.0 KB (🔴 +6.0 KB)
lib/net10.0/SkiaSharp.dll 538.0 KB → 544.0 KB (🔴 +6.0 KB)
lib/net6.0-tizen8.0/SkiaSharp.dll 527.0 KB → 533.0 KB (🔴 +6.0 KB)
lib/net9.0-macos15.0/SkiaSharp.dll 536.5 KB → 542.5 KB (🔴 +6.0 KB)
lib/net9.0-tizen8.0/SkiaSharp.dll 554.0 KB → 560.0 KB (🔴 +6.0 KB)
lib/net9.0-windows10.0.19041/SkiaSharp.dll 539.0 KB → 545.0 KB (🔴 +6.0 KB)
lib/net9.0/SkiaSharp.dll 538.0 KB → 544.0 KB (🔴 +6.0 KB)
lib/netstandard2.0/SkiaSharp.dll 518.0 KB → 524.0 KB (🔴 +6.0 KB)
ref/net462/SkiaSharp.dll 470.0 KB → 475.0 KB (🔴 +5.0 KB)
ref/net48/SkiaSharp.dll 470.0 KB → 475.0 KB (🔴 +5.0 KB)
ref/net6.0/SkiaSharp.dll 296.0 KB → 299.5 KB (🔴 +3.5 KB)
+41 more file(s)

SkiaSharp.NativeAssets.WebAssembly

File Size
🧬 wasm 5.0.6/st · libSkiaSharp.a (buildTransitive/netstandard1.0/libSkiaSharp.a/5.0.6/st/libSkiaSharp.a) 18.0 MB → 18.0 MB (🔴 +3.7 KB)
🧬 wasm 5.0.6/st,simd · libSkiaSharp.a (buildTransitive/netstandard1.0/libSkiaSharp.a/5.0.6/st,simd/libSkiaSharp.a) 18.2 MB → 18.2 MB (🔴 +3.7 KB)
🧬 wasm 5.0.6/mt · libSkiaSharp.a (buildTransitive/netstandard1.0/libSkiaSharp.a/5.0.6/mt/libSkiaSharp.a) 17.9 MB → 17.9 MB (🔴 +3.7 KB)
🧬 wasm 5.0.6/mt,simd · libSkiaSharp.a (buildTransitive/netstandard1.0/libSkiaSharp.a/5.0.6/mt,simd/libSkiaSharp.a) 18.2 MB → 18.2 MB (🔴 +3.6 KB)
🧬 wasm 3.1.56/st · libSkiaSharp.a (buildTransitive/netstandard1.0/libSkiaSharp.a/3.1.56/st/libSkiaSharp.a) 17.8 MB → 17.8 MB (🔴 +3.3 KB)
🧬 wasm 3.1.56/st,simd · libSkiaSharp.a (buildTransitive/netstandard1.0/libSkiaSharp.a/3.1.56/st,simd/libSkiaSharp.a) 18.1 MB → 18.1 MB (🔴 +3.3 KB)
🧬 wasm 3.1.56/mt · libSkiaSharp.a (buildTransitive/netstandard1.0/libSkiaSharp.a/3.1.56/mt/libSkiaSharp.a) 17.8 MB → 17.8 MB (🔴 +3.2 KB)
🧬 wasm 3.1.56/mt,simd · libSkiaSharp.a (buildTransitive/netstandard1.0/libSkiaSharp.a/3.1.56/mt,simd/libSkiaSharp.a) 18.0 MB → 18.0 MB (🔴 +3.2 KB)

SkiaSharp.NativeAssets.Win32

File Size
runtimes/win-x86/native/libSkiaSharp.pdb 97.1 MB → 97.1 MB (🔴 +72.0 KB)
runtimes/win-arm64/native/libSkiaSharp.pdb 91.2 MB → 91.2 MB (🔴 +60.0 KB)
runtimes/win-x64/native/libSkiaSharp.pdb 94.3 MB → 94.4 MB (🔴 +44.0 KB)
🧬 win-x64 (runtimes/win-x64/native/libSkiaSharp.dll) 12.8 MB → 12.8 MB (🔴 +9.0 KB)
🧬 win-arm64 (runtimes/win-arm64/native/libSkiaSharp.dll) 11.0 MB → 11.0 MB (🔴 +8.5 KB)
🧬 win-x86 (runtimes/win-x86/native/libSkiaSharp.dll) 11.1 MB → 11.1 MB (🔴 +7.5 KB)

SkiaSharp.NativeAssets.WinUI

File Size
runtimes/win-arm64/native/libGLESv2.pdb 64.5 MB → 64.4 MB (🟢 −80.0 KB)
runtimes/win-x64/native/libGLESv2.pdb 66.6 MB → 66.6 MB (🟢 −48.0 KB)
runtimes/win-x86/native/libGLESv2.pdb 67.2 MB → 67.2 MB (🟢 −32.0 KB)

Informational only — this never blocks the PR. Native binaries are labelled by os/arch.

mattleibow pushed a commit that referenced this pull request Aug 11, 2026
Carve the reviewed native Graphite views package from the combined Graphite
views work and add direct native Basic samples for Android, iOS, Mac Catalyst,
macOS, and tvOS. Gate Android below API 24 and keep the sample render loops
lifecycle-aware and failure-reporting.

Related: #4721
Requires: #4729
Requires: mono/skia#345

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: dd83f08e-1222-4b30-b315-1a5c2103463a
@mattleibow

Copy link
Copy Markdown
Contributor Author

Split follow-ups:

Review/merge order: #4729#4734#4739.

@mattleibow

Copy link
Copy Markdown
Contributor Author

The view work has been restaged around this interop PR:

The old cumulative #4734/#4739 drafts are superseded.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants