Add the SKMesh API (custom vertex-mesh drawing) - #4553
Open
ramezgerges wants to merge 8 commits into
Open
Conversation
Implements custom vertex mesh drawing with SkSL shaders, mirroring the SKRuntimeEffect API pattern with Create/Build factories, Uniforms/Children properties, and a builder class. New types: SKMeshSpecification, SKMesh, SKMeshVertexBuffer, SKMeshIndexBuffer, SKMeshBuilder, SKMeshMode, SKMeshSpecificationAttributeType/VaryingType. C API uses a builder pattern (sk_mesh_new + setters + sk_mesh_validate) with all P/Invoke calls ≤4 params for WASM interpreter compatibility. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- SKMeshSpecification.Build() now returns SKMeshBuilder (was SKMeshSpecification), matching SKRuntimeEffect.BuildShader/BuildColorFilter/BuildBlender pattern - SKMeshBuilder.Dispose() now disposes Specification (builder owns it), matching SKRuntimeEffectBuilder.Dispose() which disposes Effect - Nullable annotations on Create/ToMesh/ToMeshIndexed out parameters and nullable SKData/SKRuntimeEffect params — eliminates all CS8604/CS8625 warnings - Add BuildReturnsMeshBuilder test to cover the new return type - Update builder tests to not double-using spec (builder owns it) - Rewrite MeshSample to use Build() factory, cache builder across frames, and animate with a cycling color uniform over an indexed quad mesh - Rebase onto origin/main (skia submodule rebased onto origin/skiasharp) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Port the mesh sample from the Skia mesh2d demo featuring: - NxN configurable grid with image texture (baboon.png) - Four animated deformations: Squircle, Twirl, Wiggle, Cylinder - Wireframe overlay toggle - SkSL vertex/fragment shaders with UV coordinates Also fix nullable reference type warnings introduced by rebase: - Make GetObject(), Make(), Build(), BuildIndexed(), ToMesh(), ToMeshIndexed() return nullable types - Initialize field defaults for uniformNames/childNames - Fix redundant null-conditional on errorString Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- SkBitmapDevice::drawMesh() is a no-op in upstream Skia (GPU only) - Updated pixel-readback tests to verify creation + no-crash on CPU - Deferred MeshSample resource loading to first draw for WASM stability - Used Create() instead of Build() for graceful failure handling Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The draft PR's mesh tests only asserted construction/validation and "does not crash" on a CPU surface — where SkMesh drawing is a documented no-op — so the feature's core purpose (rendering) was never verified. Replace the misleadingly-named MeshRendersRedPixelWithColorShader (which rendered nothing and asserted no pixel) with real coverage on a GPU-backed surface: - MeshRendersRedPixelOnGpuSurface: renders the mesh via a GL context and asserts the output pixels are actually red. - DrawMeshDefaultPaintModulatesToBlack: pins the "black by default" gotcha (mesh colour is modulated by the paint colour; white paint is required for the mesh's own colour to show). - DrawMeshOnRasterSurfaceIsNoOp: makes the CPU/raster no-op an explicit assertion (canvas unchanged) instead of a comment. GPU tests skip gracefully where no GL context is available; verified here against Mesa llvmpipe (software GL 4.5). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Uno gallery's browser-wasm head could not resolve the in-tree SkiaSharp/ HarfBuzz native: IncludeNativeAssets only handled the legacy Uno WASM (UnoRuntimeIdentifier=WebAssembly), which Uno 6.x no longer sets — it now uses the .NET WebAssembly SDK with UnoUIRuntimeIdentifier=Skia. As a result the app booted but threw TypeInitialization for SkiaSharp.SkiaApi (native never linked). Uno's Skia-WASM targets link the native through the @(SkiaSharpStaticLibrary) / @(HarfBuzzSharpStaticLibrary) items (normally set by the NativeAssets NuGet, which the in-tree gallery excludes). Populate those items from output/native/wasm for the IsUnoHead + browser-wasm case. A dedicated binary-type property is used (not the shared _SkiaSharpNativeBinaryType) because Uno also sets UsingMicrosoftNETSdkWebAssembly, whose block would otherwise clobber it to a non-SIMD variant; Uno's WASM runtime is always SIMD. Verified: `dotnet publish -f net10.0-browserwasm` now links libSkiaSharp.a (3.1.56/st,simd) and the gallery boots headlessly with the Custom Mesh (SKMesh) sample. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The uniformNames/childNames cache fields were initialized to Array.Empty<string>(), which defeated the `??=` lazy-initialization in the Uniforms/Children properties: GetUniformNames()/GetChildrenNames() were never called, so both properties always returned empty. As a result, setting a declared mesh uniform by name (builder.Uniforms["uImageSize"] = ...) always threw ArgumentOutOfRangeException even though the native spec exposed it. Make the fields nullable so the lazy initialization actually runs. Adds a regression test asserting that a spec with a declared uniform enumerates it (UniformSize/Uniforms) and can be set via the builder. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
MeshSample sets IsAnimated => true but did not override OnUpdate.
CanvasSampleBase's animation loop runs, for animated samples,
`while (!cancelled) { await OnUpdate(token); new Task(Refresh).Start(scheduler); }`.
The default OnUpdate returns Task.CompletedTask instantly, so with no
override the loop spun with zero delay and queued Refresh tasks to the
UI scheduler far faster than they could drain. On single-threaded
WebAssembly this floods the managed heap until it hits the 2 GB wasm
cap, aborting with "GC could not allocate ... for major heap section".
Override OnUpdate with a ~60 FPS delay, matching every other animated
sample (ShaderPlayground, ShaderCrossFade, LottiePlayer, GifPlayer).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
📦 Try the packages from this PRWarning 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 -- 4553PowerShell / Windows: iex "& { $(irm https://raw.githubusercontent.com/mono/SkiaSharp/main/scripts/get-skiasharp-pr.ps1) } 4553"Step 2 — Add the local NuGet source dotnet nuget add source ~/.skiasharp/hives/pr-4553/packages --name skiasharp-pr-4553More options
Or download manually from Azure Pipelines — look for the Remove the source when you're done: dotnet nuget remove source skiasharp-pr-4553 |
Contributor
|
Hey there @@ramezgerges! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed. |
Contributor
|
/azp run |
|
Azure Pipelines will not run the associated pipelines, because the pull request was updated after the run command was issued. Review the pull request again and issue a new run command. |
2 similar comments
|
Azure Pipelines will not run the associated pipelines, because the pull request was updated after the run command was issued. Review the pull request again and issue a new run command. |
|
Azure Pipelines will not run the associated pipelines, because the pull request was updated after the run command was issued. Review the pull request again and issue a new run command. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add the SKMesh API (custom vertex-mesh drawing)
Completes #3779 and resolves #3777. Wraps Skia's
SkMesh— custom vertex meshes drivenby SkSL vertex/fragment programs — as
SKMesh,SKMeshSpecification,SKMeshBuilder,SKMeshVertexBuffer,SKMeshIndexBuffer, andSKCanvas.DrawMesh, plus mesh-specconstructors on
SKRuntimeEffectUniforms/Children.Requires the companion native C API PR mono/skia#297 (
sk_mesh_*,sk_canvas_draw_mesh);the submodule pointer in this PR references that commit.
What's in this PR
mainwith authorshippreserved (SKMesh API, builder-pattern alignment, the deformable-grid
MeshSample, and theCPU/raster test handling).
just that objects construct (raster
drawMeshis a no-op upstream, so construction-only testspassed even when nothing drew).
UnoRuntimeIdentifier=WebAssembly, so the native library is now linked via@(SkiaSharpStaticLibrary)with a dedicatedst,simdbinary-type property.Two bugs fixed to make the sample actually work on WebAssembly
SKMeshSpecificationuniforms/children never enumerated. TheuniformNames/childNamescache fields were initialized to
Array.Empty<string>(), which defeated the??=lazy-initin the
Uniforms/Childrenproperties — the enumerator was never called, so both alwaysreturned empty and
builder.Uniforms["uImageSize"] = …always threwArgumentOutOfRangeException. Fields are now nullable; added a regression test that a spec witha declared uniform enumerates and can be set.
Custom Mesh sample OOM on WebAssembly.
MeshSampleis animated but didn't overrideOnUpdate.CanvasSampleBase's animation loop callsOnUpdatethen schedules aRefresheach iteration; the default
OnUpdatereturns instantly, so with no override the loop spunwith zero delay and flooded the UI task scheduler until the managed heap hit the 2 GB wasm cap
("GC could not allocate … for major heap section"). Now overrides
OnUpdatewith a ~60 FPSdelay, like every other animated sample.
Testing
SKMeshTest— 28/28 pass on desktop GPU (llvmpipe via Xvfb), including the new render + uniformregression tests.
Uno WebAssembly galleries: renders and stays memory-stable (previously OOM'd within ~7 s).
🤖 Generated with Claude Code