documentation/architecture.md
This document explains SkiaSharp's three-layer design and how data flows between C++, C, and C#.
C# Wrapper Layer (binding/SkiaSharp/)
↓ P/Invoke
C API Layer (externals/skia/src/c/)
↓ Type casting
C++ Skia Library (externals/skia/)
Why this design?
IntPtr handles in C#HandleDictionary ensures one C# wrapper per native handleIDisposable for cleanup, finalizers as backup// C# - validates then calls P/Invoke
public void DrawRect(SKRect rect, SKPaint paint) {
if (paint == null)
throw new ArgumentNullException(nameof(paint));
SkiaApi.sk_canvas_draw_rect(Handle, &rect, paint.Handle);
}
// C API - minimal wrapper, trusts C# validation
void sk_canvas_draw_rect(sk_canvas_t* canvas, const sk_rect_t* rect, const sk_paint_t* paint) {
AsCanvas(canvas)->drawRect(*AsRect(rect), *AsPaint(paint));
}
| C++ | C API | C# P/Invoke | C# Wrapper |
|---|---|---|---|
SkCanvas* | sk_canvas_t* | IntPtr | SKCanvas |
SkPaint* | sk_paint_t* | IntPtr | SKPaint |
sk_sp<SkImage> | sk_image_t* | IntPtr | SKImage |
SkRect | sk_rect_t | SKRect | SKRect |
SkColor | sk_color_t | uint | SKColor |
Naming pattern: SkType → sk_type_t → SKType
| C++ | C API | C# |
|---|---|---|
SkCanvas::drawRect() | sk_canvas_draw_rect() | SKCanvas.DrawRect() |
SkPaint::getColor() | sk_paint_get_color() | SKPaint.Color (get) |
SkPaint::setColor() | sk_paint_set_color() | SKPaint.Color (set) |
// In sk_types_priv.h - converts between C and C++ types
AsCanvas(sk_canvas_t*) → SkCanvas*
ToCanvas(SkCanvas*) → sk_canvas_t*
AsPaint(sk_paint_t*) → SkPaint*
AsRect(sk_rect_t*) → SkRect*
| Layer | Files |
|---|---|
| C++ API | externals/skia/include/core/SkCanvas.h |
| C API header | externals/skia/include/c/sk_canvas.h |
| C API impl | externals/skia/src/c/sk_canvas.cpp |
| P/Invoke | binding/SkiaSharp/SkiaApi.generated.cs |
| C# wrapper | binding/SkiaSharp/SKCanvas.cs |
| Object Type | Thread-Safe? | Notes |
|---|---|---|
| SKCanvas, SKPaint, SKPath | ❌ No | Keep thread-local |
| SKImage, SKShader, SKTypeface | ✅ Yes | Immutable, can share |
| Object creation | ✅ Yes | Creating different objects on different threads is safe |
Rule: Don't use the same mutable object (Canvas/Paint/Path) from multiple threads.
externals/skia/src/c/*.cpp)SkiaApi.generated.cs)binding/SkiaSharp/SK*.cs)pwsh ./utils/generate.ps1 # Regenerate all
pwsh ./utils/generate.ps1 -Config libSkiaSharp.json # Regenerate specific config