Skip to content

Add SkiaSharp SKP Debugger — Blazor WASM with native DebugCanvas#3583

Draft
mattleibow wants to merge 1 commit into
mainfrom
dev/skp-debugger-wasm
Draft

Add SkiaSharp SKP Debugger — Blazor WASM with native DebugCanvas#3583
mattleibow wants to merge 1 commit into
mainfrom
dev/skp-debugger-wasm

Conversation

@mattleibow

Copy link
Copy Markdown
Contributor

Summary

A Blazor WebAssembly recreation of Google's Skia Debugger using SkiaSharp. Loads .skp files and decomposes them into individual draw commands using Skia's native DebugCanvas, running entirely in the browser via WASM — no server-side processing.

Companion PR: mono/skia#174 (C API for DebugCanvas)


What It Does

Load any .skp file → see every draw command (DrawRect, Concat44, Save, ClipPath, etc.) → step through them one by one → watch the canvas build up progressively. The same experience as https://debugger.skia.org/ but powered by SkiaSharp in Blazor WASM.

Features

  • SKP file loading with real Skia DebugCanvas introspection (not simulated)
  • Command list with positive/negative text filtering (!Save Restore hides those)
  • Step-by-step renderingDebugCanvas.DrawTo(canvas, index) renders up to command N
  • Playback controls — play/pause/step forward/back/jump to start/end
  • Command histogram — count of each command type
  • Matrix/clip display — live transform matrix and clip rect from native DebugCanvas
  • Pixel inspector — RGBA values at cursor position
  • 16× zoom view — magnified pixel grid around cursor
  • Overdraw visualization — native Skia overdraw mode
  • Clip region overlay — shows clip bounds in red
  • Origin crosshair — shows coordinate origin
  • Dark theme UI

Architecture

┌─────────────────┐     ┌────────────────────┐     ┌──────────────────┐
│  Blazor WASM    │────▶│ SkiaSharp.Debugger │────▶│ libSkiaSharp.a   │
│  (net10.0)      │     │ (netstandard2.0)   │     │ (WASM + debugger)│
│                 │     │                    │     │                  │
│ Index.razor     │     │ SKDebugCanvas.cs   │     │ sk_debugger.cpp  │
│ Components/*    │     │ DebuggerState.cs   │     │ DebugCanvas.cpp  │
│                 │     │ Models/*           │     │ DrawCommand.cpp  │
└─────────────────┘     └────────────────────┘     └──────────────────┘

Layer 1: Native C API (externals/skia/ — see mono/skia#174)

  • sk_debugger.h/cpp — 14 C API functions wrapping Skia's DebugCanvas
  • Gated behind skia_build_for_debugger=true GN flag
  • SkiaKeeper.c references prevent dead-stripping

Layer 2: C# Library (source/SkiaSharp.Debugger/)

  • SKDebugCanvas.cs — P/Invoke wrapper with IDisposable, ObjectDisposedException guards, UTF-8 JSON decoding
  • DebuggerState.cs — Pure C# state management: filtering (positive Draw/negative !Save Restore), range, stepping, histogram, toggle
  • Models/SkpCommandList.cs — JSON deserialization for Skia's command JSON format

Layer 3: Blazor WASM App (samples/Basic/BlazorWebAssembly/SkiaSharpDebugger/)

  • Index.razor — Main page: loads SKP via SKDebugCanvas, renders via DrawTo(), syncs settings
  • 7 reusable Blazor components (CommandList, PlaybackControls, HistogramPanel, MatrixClipDisplay, PixelInspector, ZoomView, SettingsPanel)
  • All components subscribe to DebuggerState.StateChanged for reactive re-rendering
  • Sample .skp files in wwwroot/skp/

How to Build

Prerequisites

  • .NET 10 SDK with wasm-tools workload
  • For native rebuild: Emscripten 3.1.56 (bundled in .NET SDK)

Run the app (using pre-built WASM natives)

dotnet cake --target=externals-download
dotnet build samples/Basic/BlazorWebAssembly/SkiaSharpDebugger/
cd samples/Basic/BlazorWebAssembly/SkiaSharpDebugger
dotnet run --urls "http://localhost:5070"

Build native macOS library with debugger support

SKIA_DEBUGGER=true dotnet cake --target=externals-macos --arch=arm64

Build native WASM library with debugger support

The WASM .a must include the debugger sources. Two approaches:

Option A: Docker (Linux, recommended for CI)

cd scripts/Docker/wasm
# Edit build-local.sh or pass SKIA_DEBUGGER=true
SKIA_DEBUGGER=true ./build-local.sh 3.1.56

Option B: Local macOS using .NET SDK's bundled Emscripten

# Set up Emscripten from .NET SDK packs
TOOLS="/usr/local/share/dotnet/packs/Microsoft.NET.Runtime.Emscripten.3.1.56.Sdk.osx-arm64/10.0.5/tools"
CACHE="/usr/local/share/dotnet/packs/Microsoft.NET.Runtime.Emscripten.3.1.56.Cache.osx-arm64/10.0.5/tools/emscripten"
export DOTNET_EMSCRIPTEN_LLVM_ROOT="$TOOLS/bin"
export DOTNET_EMSCRIPTEN_NODE_JS="$(find /usr/local/share/dotnet/packs -path '*/Node*/node' | head -1)"
export DOTNET_EMSCRIPTEN_BINARYEN_ROOT="$TOOLS"
export EM_CONFIG="$TOOLS/emscripten/.emscripten"
export EM_CACHE="$CACHE/cache"
export PATH="$TOOLS/emscripten:$TOOLS/bin:$PATH"

# Compile just the debugger .o files
SKIA="externals/skia"
CFLAGS="-std=c++17 -O2 -fvisibility=hidden -frtti -DSKIA_C_DLL -DNDEBUG -DSK_BUILD_FOR_WASM -DSK_GANESH -DSK_GL -I$SKIA -I$SKIA/include -I$SKIA/src -I$SKIA/tools"
em++ $CFLAGS -c "$SKIA/src/c/sk_debugger.cpp" -o /tmp/sk_debugger.o
em++ $CFLAGS -c "$SKIA/tools/debugger/DebugCanvas.cpp" -o /tmp/DebugCanvas.o
em++ $CFLAGS -c "$SKIA/tools/debugger/DrawCommand.cpp" -o /tmp/DrawCommand.o
em++ $CFLAGS -c "$SKIA/tools/debugger/DebugLayerManager.cpp" -o /tmp/DebugLayerManager.o
em++ $CFLAGS -c "$SKIA/tools/debugger/JsonWriteBuffer.cpp" -o /tmp/JsonWriteBuffer.o
em++ $CFLAGS -c "$SKIA/tools/UrlDataManager.cpp" -o /tmp/UrlDataManager.o

# Patch the existing WASM .a
cp output/native/wasm/libSkiaSharp.a/3.1.56/st/libSkiaSharp.a /tmp/patched.a
emar rcs /tmp/patched.a /tmp/sk_debugger.o /tmp/DebugCanvas.o /tmp/DrawCommand.o /tmp/DebugLayerManager.o /tmp/JsonWriteBuffer.o /tmp/UrlDataManager.o
cp /tmp/patched.a output/native/wasm/libSkiaSharp.a/3.1.56/st/libSkiaSharp.a

Run tests

dotnet test source/SkiaSharp.Debugger/SkiaSharp.Debugger.Tests/
# 132 tests: state management, JSON parsing, SKP generation, native DebugCanvas

Generate sample SKP files (writes to wwwroot/skp/)

dotnet test source/SkiaSharp.Debugger/SkiaSharp.Debugger.Tests/ --filter "GenerateAllSkpFiles"

Files Changed

New Files

Path Description
source/SkiaSharp.Debugger/SkiaSharp.Debugger/ Class library (SKDebugCanvas, DebuggerState, Models)
source/SkiaSharp.Debugger/SkiaSharp.Debugger.Tests/ 132 unit tests
samples/Basic/BlazorWebAssembly/SkiaSharpDebugger/ Full Blazor WASM app

Modified Files

Path Change
scripts/cake/native-shared.cake SKIA_DEBUGGER env var → skia_build_for_debugger GN flag
native/macos/build.cake enableDebugger variable for macOS builds
externals/skia Points to dev/debugger-c-api branch (mono/skia#174)

A Blazor WebAssembly recreation of Google's Skia Debugger
(https://debugger.skia.org/) using SkiaSharp. Loads .skp files and
decomposes them into individual draw commands using Skia's native
DebugCanvas, running entirely in the browser via WASM.

Components:
- SkiaSharp.Debugger library (netstandard2.0)
  - SKDebugCanvas: P/Invoke wrapper for native DebugCanvas
  - DebuggerState: Pure C# state management with filtering/stepping
  - Models/SkpCommandList: JSON deserialization for Skia command data

- SkiaSharpDebugger Blazor WASM app (net10.0)
  - SKP file loading with real native introspection
  - Command list with filtering (positive/negative text filters)
  - Step-by-step rendering via DebugCanvas.DrawTo()
  - Playback controls (play/pause/step/jump)
  - Command histogram
  - Matrix/clip state display (live from native DebugCanvas)
  - Pixel inspector with RGBA values
  - 16x zoom view
  - Dark theme UI matching VS Code aesthetic
  - Overdraw visualization, clip region overlay, origin crosshair

- 132 unit tests covering:
  - JSON command parsing
  - State management (filtering, stepping, range, histogram)
  - SKP generation and serialization
  - Native DebugCanvas integration (7 tests)

Build changes:
- native-shared.cake: SKIA_DEBUGGER env var / --debugger flag
- native/macos/build.cake: enableDebugger variable (kept for reference)
- externals/skia submodule: points to dev/debugger-c-api branch

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mattleibow mattleibow marked this pull request as draft March 26, 2026 13:51
@mattleibow mattleibow mentioned this pull request May 8, 2026
11 tasks
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.

1 participant