| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
ProGPU is a high-performance, GPU-first UI framework and composition substrate for .NET, built on top of Silk.NET and WebGPU (wgpu-native). It provides a lightweight, low-allocation alternative to traditional heavyweight UI frameworks by routing all vector graphics, text layout, and composition operations directly to the GPU using native WebGPU draw pipelines.
ProGPU release packages are built from eng/progpu-package-list.sh by the Release GitHub Actions workflow. Samples, tests, diagnostics, and framework shim projects are intentionally not packed.
| Package | Purpose | Project |
|---|---|---|
| ProGPU.Backend | WebGPU device, swapchain, Silk.NET windowing, and platform backend services. | src/ProGPU.Backend/ProGPU.Backend.csproj |
| ProGPU.DirectX | DirectX-compatible facade and shader-oriented API surface implemented on ProGPU/WebGPU. | src/ProGPU.DirectX/ProGPU.DirectX.csproj |
| ProGPU.Transpiler | Shader/source transformation helpers used by generated GPU pipelines. | src/ProGPU.Transpiler/ProGPU.Transpiler.csproj |
| ProGPU.Compute | Compute pipeline helpers for GPU-side effects, acceleration, and future hit-test indexes. | src/ProGPU.Compute/ProGPU.Compute.csproj |
| ProGPU.Vector | Vector primitives, paths, geometry, brushes, pens, and rasterization data models. | src/ProGPU.Vector/ProGPU.Vector.csproj |
| ProGPU.Text | Text layout, glyph metrics, and GPU-ready text rendering helpers. | src/ProGPU.Text/ProGPU.Text.csproj |
| ProGPU.Scene | Scene graph, compositor commands, retained visuals, effects, and presentation primitives. | src/ProGPU.Scene/ProGPU.Scene.csproj |
| ProGPU.Layout | Measure/arrange layout substrate shared by higher-level UI adapters. | src/ProGPU.Layout/ProGPU.Layout.csproj |
| ProGPU.Virtualization | Virtualization helpers for large retained visual and item surfaces. | src/ProGPU.Virtualization/ProGPU.Virtualization.csproj |
| ProGPU.WinUI | WinUI-shaped controls and app model implemented on ProGPU. | src/ProGPU.WinUI/ProGPU.WinUI.csproj |
| ProGPU.WinUI.Charts | Chart controls and chart rendering primitives for the WinUI-shaped layer. | src/ProGPU.WinUI.Charts/ProGPU.WinUI.Charts.csproj |
| ProGPU.WinUI.Designer | Designer/editor controls and diagnostics for ProGPU WinUI surfaces. | src/ProGPU.WinUI.Designer/ProGPU.WinUI.Designer.csproj |
| ProGPU.Avalonia | Avalonia integration and compositor backend adapter. | src/ProGPU.Avalonia/ProGPU.Avalonia.csproj |
| ProGPU.Uno | Uno/WinUI integration and compositor backend adapter. | src/ProGPU.Uno/ProGPU.Uno.csproj |
| ProGPU.Dxf | DXF import/rendering support for ProGPU vector scenes. | src/ProGPU.Dxf/ProGPU.Dxf.csproj |
| ProGPU.SkiaSharp | ProGPU-backed portable SkiaSharp compatibility shim used by drawing and imaging adapters. | src/SkiaSharp/SkiaSharp.csproj |
| ProGPU.System.Drawing.Common | ProGPU-backed portable System.Drawing.Common compatibility shim for LibreWinForms and GDI-style callers. | src/System.Drawing.Common/System.Drawing.Common.csproj |
| LibreWPF.Interop | LibreWPF portable interop contracts consumed by the ProGPU/Silk.NET SDK lane. | src/ProGPU.Wpf.Interop/ProGPU.Wpf.Interop.csproj |
Local package build:
PROGPU_PACKAGE_VERSION=0.1.0-preview.1 ./eng/progpu-pack.shThe release workflow validates docs, restores, builds, tests, packs .nupkg/.snupkg artifacts, and can publish to NuGet.org when NUGET_API_KEY is configured. See docs/release.md.
The ProGPU framework is built in a modular, layered stack that bridges native graphics APIs and system windowing up to a modern, declarative WinUI-compatible user interface layer.
graph TD
subgraph L6 ["Layer 6: Application Layer"]
App["Gallery Dashboard / LOL/s & MotionMark Benchmarks"]
end
subgraph L5 ["Layer 5: WinUI Framework Layer"]
Controls["Grid, StackPanel, ScrollViewer, Border, Pivot, RichTextBlock"]
FE["FrameworkElement"]
LN["LayoutNode - Measure & Arrange Sizing Negotiation"]
end
subgraph L4 ["Layer 4: Scene Graph & Effects Layer"]
CV["ContainerVisual / DrawingVisual / Visual"]
ILN["ILayoutNode Interface - Decoupled Invalidation"]
FX["GPGPU Multi-Pass Effects Pipeline - Blur & DropShadow"]
end
subgraph L3 ["Layer 3: Compositor, Text & GPGPU Rasterizer"]
Comp["Compositor - Span-Based Vertex/Index Mesh Compiler"]
Text["TTF Line Layout & Paragraph Wrapping Engine"]
Rast["Compute-Bound 4x SSAA Analytical Path Rasterizer"]
end
subgraph L2 ["Layer 2: Graphics Infrastructure"]
Wgpu["WgpuContext - WebGPU Adapter/Device & Swapchain Management"]
end
subgraph L1 ["Layer 1: System & Windowing"]
Silk["Silk.NET Windowing & GLFW OS Event Loop"]
end
App --> Controls
Controls --> FE
FE --> LN
LN --> CV
CV --> ILN
CV --> FX
ILN --> Comp
FX --> Rast
Comp --> Rast
Rast --> Wgpu
Wgpu --> Silk
Our work introduces eleven core rendering and performance optimization pillars that collectively transform frame times, CPU allocation metrics, visual fidelity, and event dispatcher throughput.
Traditional layout systems recursively traverse the entire scene graph every frame to negotiate sizing, causing massive $O(N)$ CPU overhead on complex visual trees even when the UI is static.
ProGPU introduces a cached sizing negotiation model that short-circuits measurements using layout dirty flags and cached input boundaries:
flowchart TD
Start["Measure Pass availableSize"] --> Cached{"_isMeasureValid and availableSize == _previousAvailableSize?"}
Cached -- Yes --> O1Exit["O1 Early Exit - Return Cached DesiredSize"]
Cached -- No --> Calc["Calculate Margin Insets & Bounds Constraints"]
Calc --> Override["Execute MeasureOverride child passes recursively"]
Override --> CacheResult["Store DesiredSize, _previousAvailableSize & set _isMeasureValid = true"]
CacheResult --> ArrangeStart["Arrange Pass finalRect"]
ArrangeStart --> CachedArr{"_isArrangeValid and _isMeasureValid and finalRect == _previousFinalRect?"}
CachedArr -- Yes --> O1ExitArr["O1 Early Exit - Return Immediately"]
CachedArr -- No --> Align["Calculate Offset Coordinates & Horizontal/Vertical Alignments"]
Align --> OverrideArr["Execute ArrangeOverride child placements recursively"]
OverrideArr --> CacheResultArr["Store Offset/Size, _previousFinalRect & set _isArrangeValid = true"]
To prevent circular dependencies between the ProGPU.Scene assembly (base visual layer) and the ProGPU.Layout assembly (WinUI framework layer), the ILayoutNode interface is defined in ProGPU.Scene:
public interface ILayoutNode
{
void InvalidateMeasure();
}Visual tree mutation methods (ContainerVisual.AddChild, RemoveChild, ClearChildren) check if this implements ILayoutNode. If so, they invoke InvalidateMeasure(), ensuring that any changes in visual tree structure automatically mark the layout path dirty without explicit parent layout references.
Layout caching relies heavily on comparing boundary structs (Thickness and Rect) on every node. Standard C# struct comparison utilizes generic ValueType.Equals, which triggers CPU reflection, runtime boxing, and high memory allocations.
To eliminate this bottleneck, we implemented type-safe, non-boxing, custom equality overloads for both structs:
Each struct now overrides Equals(Thickness/Rect other), Equals(object? obj), GetHashCode(), and provides high-speed operators:
public bool Equals(Rect other)
{
return X == other.X && Y == other.Y && Width == other.Width && Height == other.Height;
}
public static bool operator ==(Rect left, Rect right)
{
return left.Equals(right);
}
public static bool operator !=(Rect left, Rect right)
{
return !left.Equals(right);
}These overloads compile down to direct float comparison instructions, achieving zero-allocation, ultra-fast boundary checks.
To allow graphics and layout benchmarks to be evaluated at their true physical limit, we disabled vertical synchronization (VSync) throttling across all layers of the GPU pipeline:
options.VSync = false;PresentMode presentMode = PresentMode.Fifo; // Fallback VSync
for (uint i = 0; i < capabilities.PresentModeCount; i++)
{
if (capabilities.PresentModes[i] == PresentMode.Immediate)
{
presentMode = PresentMode.Immediate; // VSync Off
break;
}
}This enables the graphics swapchain to present frames as quickly as the GPU queue is filled, releasing the 60 FPS constraint and allowing framerates to soar into the hundreds or thousands of FPS.
The LOL/s benchmark stresses the visual framework by constantly removing and adding hundreds of poolable text controls to a canvas using a background thread loop.
flowchart TD
Start["Background Task Loop"] --> CheckBackpressure{"UIThread.PendingCount > 100?"}
CheckBackpressure -- Yes --> Sleep["Thread.Sleep 1ms / Release Monitor Locks"]
Sleep --> Start
CheckBackpressure -- No --> Post["Post Action immediately / No Sleep"]
Post --> UIThread["UIThread.RunPending - Main Thread drains queue"]
UIThread --> AddChild["AddChild/RemoveChild visual tree mutation"]
In real-time GPU-based vector rendering, compiling high-level primitives (such as Rectangles, Ellipses, Rounded Rectangles, Paths, Lines, and Bezier curves) into dynamic vertex and index buffers is a major CPU bottleneck. Standard implementation using sequential .Add(...) calls on List<T> invokes continuous bounds checks, potential array resizing/reallocations, and element copying overhead.
To maximize throughput, the Compositor is optimized using high-performance Span<T> memory writes:
int originalVertexCount = _vectorVerticesList.Count;
int vertexToAdd = 2 * (N + 1);
CollectionsMarshal.SetCount(_vectorVerticesList, originalVertexCount + vertexToAdd);
var vertexSpan = CollectionsMarshal.AsSpan(_vectorVerticesList).Slice(originalVertexCount, vertexToAdd);
vertexSpan.Fill(baseVertex);This ensures that the mesh compiler achieves zero-allocation dynamic buffer construction, minimal instruction-level overhead, and runs at near-native C-speed.
In traditional UI and vector engines, every active visual element in an animation loop is modeled as a heap-allocated class object. During high-count stress tests (such as the MotionMark benchmark rendering thousands of dynamically moving curves), these allocations put immense pressure on the .NET Garbage Collector (GC), leading to periodic micro-stutters and frame drops.
ProGPU eliminates this overhead using lightweight structs and batched pipeline groupings:
public struct Element
{
public SegmentKind Kind;
public GridPoint Start;
public GridPoint Control1;
public GridPoint Control2;
public GridPoint End;
public Vector4 Color;
public float Width;
public bool Split;
public SolidColorBrush CachedBrush;
public Pen CachedPen;
}Standard graphics engines struggle to apply dynamic blurred effects (such as Gaussian backdrop blurs, soft ambient drop shadows, and neon glowing halos) to standard layout elements in real-time due to high composition and memory transfer overhead. ProGPU overcomes this with a multi-pass offscreen composition and compute processing system.
graph TD
Subtree["Subtree Render Pass"] -->|Draw Elements 1x MSAA| Src["Source Offscreen Texture"]
Src -->|Horiz. Dispatch| HCompute["Gaussian Blur Compute Shader Pass 1"]
HCompute -->|Vert. Dispatch| VCompute["Gaussian Blur Compute Shader Pass 2"]
VCompute -->|Output Framebuffer| Dest["Destination Blurs/Shadows Texture"]
Dest -->|Matrix Align and Z-Order Bind| Framebuffer["Primary Swapchain Framebuffer"]
To bypass CPU bottlenecks (e.g. flattening Bezier curves into thousands of lines and performing heavy triangulation), ProGPU integrates a pure GPU-bound vector path rasterizer. The engine computes vector fills analytically directly inside custom WebGPU WGSL compute shaders.
To satisfy WebGPU/WGSL uniform and storage buffer packing requirements, layout metrics are organized into sequentially packed structs matching exact 16-byte memory alignments:
[StructLayout(LayoutKind.Sequential, Pack = 16)]
public struct PathUniforms
{
public float XStart; public float YStart;
public float Scale; public uint PathIndex;
public uint AtlasX; public uint AtlasY;
public uint Width; public uint Height;
}
[StructLayout(LayoutKind.Sequential, Pack = 16)]
public struct GpuPathRecord
{
public uint StartSegment; public uint SegmentCount;
public float MinX; public float MinY;
public float MaxX; public float MaxY;
public uint Pad0; public uint Pad1;
}
[StructLayout(LayoutKind.Sequential, Pack = 16)]
public struct GpuPathSegment
{
public Vector2 P0; public Vector2 P1;
public Vector2 P2; public Vector2 P3;
public uint SegmentType; public uint Pad0;
public uint Pad1; public uint Pad2;
}The rasterizer counts curve intersections analytically using a horizontal ray casting winding-number algorithm directly in WGSL:
if (px < inst.screenMinX || px > inst.screenMaxX || py < inst.screenMinY || py > inst.screenMaxY) {
continue;
}Standard Signed Distance Field (SDF) rendering often clips the outer half of strokes or the edges of anti-aliasing gradients because the generated quad boundaries are drawn exactly at the shape's mathematical dimensions. This limits pixel operations outside the bounding box, resulting in a rough, aliased border.
To achieve state-of-the-art vector quality with zero performance degradation, we implemented a dual-stage quad inflation and pixel-distance anti-aliasing framework:
let d_pixels = abs(input.gridIndex);
let d_shape = d_pixels - input.strokeThickness * 0.5;
shapeAlpha = 1.0 - smoothstep(-0.5, 0.5, d_shape);ProGPU implements a lightweight, high-performance, and memory-safe theming, styling, and templating engine designed to emulate the logical capabilities of WinUI 3 but operating with minimal CPU and memory overhead.
flowchart TD
Reg["DependencyProperty.Register"] -->|Sequential Indexing| DP["Index-Based Property Mapped Arrays"]
DP -->|Precedence Resolution| GetVal["O1 GetValue Precedence Sweep"]
Theme["ThemeManager.ThemeChanged"] -->|Lazy Invalidation| Dirty["Set IsThemeDirty = true"]
Dirty -->|On-Demand Query| GetVal
subgraph Storage ["O(1) Parallel Contiguous Value and Theme Arrays"]
Local["_localValues"]
Style["_styleValues"]
DStyle["_defaultStyleValues"]
LocalTheme["_localThemeResources"]
StyleTheme["_styleThemeResources"]
DStyleTheme["_defaultStyleThemeResources"]
end
Traditional XAML frameworks store DependencyObject property values in heavy dictionaries (Dictionary<DependencyProperty, object>), which trigger expensive hash calculation, collisions, and lookup overhead inside tight render or layout loops. ProGPU bypasses dictionaries entirely by introducing sequential indexing:
Eagerly traversing and updating dynamic brushes across the entire visual tree on every theme change triggers substantial CPU frame stutters. ProGPU bypasses this via a lazy evaluation pipeline:
To support lightweight control customization without the heavy reflection, expression compilation, or string-matching of traditional bindings:
To support robust diagnostic capabilities:
Traditional GPU engines suffer from low-resolution stretch blurriness on macOS high-DPI (Retina) screens because they configure the SwapChain to match logical coordinates, letting the operating system scale the output. ProGPU achieves true macOS Retina rendering quality while maintaining high performance through four main pillars:
In high-performance GPU-bound UI frameworks, recursively traversing large, static visual subtrees (such as complex sidebar menus, navigation drawers, and presentation panels) every frame at double physical coordinates (FramebufferSize) on macOS Retina screens incurs heavy CPU-to-GPU overhead (layout traversal, vertex mesh generation, matrix multiplications, draw call issuance, and constant buffer uploads).
ProGPU introduces Layered High-DPI Visual Caching (CacheAsLayer) to completely eliminate redundant rendering loops for static or rarely modified subtrees:
flowchart TD
Compile["CompileVisualTree node"] --> CacheChecked{"node.CacheAsLayer and Compositor.IsCacheAsLayerEnabled?"}
CacheChecked -- No --> NormalPass["Standard Pass: Recurse Visual Subtree and Compile Primitives"]
CacheChecked -- Yes --> DirtyCheck{"node.IsDirty or node.LayerTexture == null?"}
DirtyCheck -- Yes --> RenderOff["Execute RenderOffscreen centered in node.LayerTexture"]
RenderOff --> MarkClean["Set node.IsDirty = false"]
MarkClean --> DrawTexture["Compile single DrawTexture command onto Swapchain"]
DirtyCheck -- No --> DrawTexture
In retained scene graphs with interleaved primitive types (such as vector geometries, offscreen computer-generated textures, and rich text visual elements), simple bulk-draw grouping causes Z-order overlap bugs. If all textures or all texts are batched and drawn at the very end of layer compilation, solid backgrounds or overlay vectors can draw on top of pre-rendered textures, resulting in black or empty areas.
ProGPU implements a Dynamic Z-Ordered Draw Call Batching mechanism within Compositor.cs to achieve optimal batching performance while strictly preserving visual Z-order:
High-performance vector rendering loops are highly sensitive to Garbage Collection (GC) pressure. Passing coordinate arrays (such as Vector2[] for complex polylines, curves, or CAD structures) on every frame forces heap allocation and copying, resulting in massive GC thrashing.
ProGPU completely eliminates this overhead by introducing a zero-allocation vector drawing engine driven by ReadOnlySpan<T> and a Skia-like GpuPicture command caching architecture:
flowchart TD
subgraph AllocPool ["Zero-Allocation Frame Draw (Pooling)"]
DrawCall["DrawPolyline(Pen, ReadOnlySpan<Vector2> points)"] --> GetPool["Acquire continuous PointBuffer from DrawingContext"]
GetPool --> CopySpan["Copy points data in bulk using high-speed Span.CopyTo"]
CopySpan --> RecordCmd["Record RenderCommand with PointBufferOffset and PointBufferCount"]
end
subgraph CacheSystem ["Pre-Recorded Caching Loop (GpuPicture)"]
RecStart["GpuPictureRecorder.BeginRecording(bounds)"] --> RecDraw["Record vector commands into local buffers once"]
RecDraw --> RecEnd["EndRecording() compiles into immutable GpuPicture"]
RecEnd --> DrawCache["context.DrawPicture(picture, cameraViewMatrix)"]
DrawCache --> CompositorPlay["Compositor compiles and plays back directly in-place (Zero-Copy)"]
end
Since ReadOnlySpan<T> is a stack-only ref struct, it cannot be stored on the heap or inside standard lists. To allow zero-allocation span-based rendering, DrawingContext maintains internal pre-allocated continuous memory lists:
On every frame refresh, calling .Clear() on these buffers resets their logical Count to 0 but retains their internal backing array capacity. Drawing coordinates are copied into these pre-allocated pools using high-speed bulk Span<T>.CopyTo operations. As long as capacity is sufficient, frame-by-frame rendering runs at near-native speed with absolutely zero heap allocations.
To support both real-time dynamic rendering (where coordinates live in the active DrawingContext pools) and cached playback (where coordinates live in static arrays), we introduce the IRenderDataProvider interface:
public interface IRenderDataProvider
{
ReadOnlySpan<Vector2> GetPoints(int offset, int count);
ReadOnlySpan<double> GetDoubles(int offset, int count);
ReadOnlySpan<Line3D> GetLines3D(int offset, int count);
ReadOnlySpan<float> GetFloats(int offset, int count);
}Both DrawingContext and GpuPicture implement IRenderDataProvider. Inside WebGPU mesh compilation, the compositor queries coordinate spans directly from the active provider using the offsets and counts recorded in the RenderCommand.
// Draws polylines or polygon outlines directly from stack memory
public void DrawPolyline(Pen pen, ReadOnlySpan<Vector2> points, bool isClosed = false);
// Draws quadratic or cubic B-Spline curves
public void DrawSpline(Pen pen, ReadOnlySpan<Vector2> controlPoints, ReadOnlySpan<double> knots, int degree);
// Draws rational, weighted NURBS curves
public void DrawSpline(Pen pen, ReadOnlySpan<Vector2> controlPoints, ReadOnlySpan<double> knots, ReadOnlySpan<double> weights, int degree, bool isClosed);
// Draws 3D ACIS solids or wireframe boundaries
public void DrawAcisSolid(Pen pen, ReadOnlySpan<Line3D> edges, Matrix4x4 modelTransform);
// Hardware-accelerated dynamic chart line series
public void DrawGpuLineSeries(ReadOnlySpan<float> interleavedCoords, int pointsCount, float thickness, Brush brush);
// Hardware-accelerated dynamic chart scatter series
public void DrawGpuScatterSeries(ReadOnlySpan<float> interleavedCoords, int pointsCount, float radius, Brush brush);Wraps standard heap-allocated arrays into ReadOnlySpan<T> using new ReadOnlySpan<T>(array) and forwards to the high-performance pipeline. Assigns legacy fields (SplineWeights, Edges3D) on the created RenderCommand structures to preserve 100% test compatibility and visual tree diagnostics:
public void DrawPolyline(Pen pen, Vector2[] points, bool isClosed = false);
public void DrawSpline(Pen pen, Vector2[] controlPoints, double[] knots, int degree);
public void DrawSpline(Pen pen, Vector2[] controlPoints, double[] knots, double[]? weights, int degree, bool isClosed);
public void DrawAcisSolid(Pen pen, List<Line3D> edges, Matrix4x4 modelTransform);High-performance viewport virtualization is highly sensitive to coordinate math re-calculation and z-order sorting. To guarantee flawless macOS Retina-quality scrollbar overlay Z-order depth, precise boundary clipping, and locked 60 FPS scrolling speeds, ProGPU implements a WinUI-Style Cooperating Scroll Virtualization architecture:
flowchart TD
subgraph Parent ["ItemsControl (Templated Control)"]
Border["Border (Chrome Background)"] --> ScrollViewer["ScrollViewer (Viewport Clipping)"]
end
subgraph Child ["VirtualizingPanel (Cooperating Child)"]
Panel["UniformVirtualizingGridPanel / VirtualizingStackPanel"]
end
ScrollViewer -->|Hosts Panel inside Content| Panel
Panel -->|Traverses Visual Tree| ParentQuery{"Parent ScrollViewer found?"}
ParentQuery -- Yes --> Cooperate["Cooperating Mode: Dynamic Offset Bindings"]
ParentQuery -- No --> Standalone["Standalone Mode: Fallback ScrollBarOverlay child"]
Cooperate -->|MeasurePass: DesiredSize.Y = TotalVirtualHeight| ScrollViewer
ScrollViewer -->|Updates scrollbars and sets VerticalOffset| Cooperate
ScrollViewer -->|Physically translates panel by -VerticalOffset| Panel
Cooperate -->|UpdateViewport: Render cells at absolute position row*ItemHeight| Panel
To eliminate floating-point coordinate drift and keep layout compilation cycles fast:
CAD drawings (like DXF files) contain hundreds of thousands or millions of vector elements (lines, circles, polyline arcs, splines, and complex hatches). Recursively compiling these vector primitives from a dynamic visual tree every frame on camera changes (zoom/pan) is CPU-prohibitive.
ProGPU introduces Hardware-Accelerated Static WebGPU Buffers (Option B) which compiles all vector primitives once into a static, GPU-mapped vertex/index store (DxfStaticBuffer). Panning and zooming are executed entirely on the GPU via updates to the viewport uniforms, maintaining a locked 60+ FPS on massive, million-entity CAD models.
While static geometry scales infinitely on the GPU, TrueType Font (TTF) text is drawn as textured quads pointing to a bitmap-cached GlyphAtlas. Zooming in stretches these pre-rendered quads, causing bilinear texture blur because the glyph atlas texture was rasterized at a static zoom scale.
ProGPU resolves this by implementing Crisp Static Text Buffers via Dynamic Re-compilation:
flowchart TD
ZoomChange{"Context.Zoom != _lastZoom?"}
ZoomChange -- No --> DrawStatic["Draw Static Dxf Buffer - 100% GPU Bound (Panning Free)"]
ZoomChange -- Yes --> Recompile["Trigger RecompileStaticText on CPU"]
Recompile --> ScaleDPI["Scale effective dpiScale = _currentDpiScale * Context.Zoom"]
ScaleDPI --> RasterGlyph["Rasterize Glyph at physical FontSize * dpiScale * Zoom inside Atlas"]
RasterGlyph --> ModelSpace["Divide quad vertex coords by effective dpiScale (cancel out Zoom)"]
ModelSpace --> WriteGPU["Dynamic Copy-on-Write vertex/index re-upload to GpuBuffer"]
WriteGPU --> DrawStatic
To support instantaneous zoom transitions on massive CAD models containing thousands of text elements (such as Schemat IOS Karvina CZ.dxf), ProGPU integrates three advanced graphics-pipeline optimizations:
$O(\text{TextCount})$ Pre-Filtered Text Records Cache:
public struct StaticTextRecord
{
public RenderCommand Command;
public Matrix4x4 Transform;
}Discrete Font Snapping & Quad Scaling:
WebGPU Queue & Driver Submission Batching:
To eliminate the continuous CPU memory allocation overhead of creating small, temporary GPU uniform buffers on every render pass, we implemented a Pre-allocated Ring Uniform Buffer pattern in both GlyphAtlas and PathAtlas:
_context.Wgpu.QueueWriteBuffer(_context.Queue, _uniformRingBuffer.BufferPtr, _ringOffset, &uniforms, (uint)Marshal.SizeOf<GlyphUniforms>());Updating dense vector meshes and text quads during snapped zoom events can cause severe CPU-GPU hardware execution stalls. If the CPU disposes and recreates vertex/index buffers while the GPU command queue is actively reading from them, the graphics driver is forced to block CPU execution to synchronize hardware lifecycles.
To prevent these stalls and achieve perfectly fluid rendering, we implemented a Double-Buffering Swapchain pattern:
var tempVertexBuffer = TextVertexBuffer;
TextVertexBuffer = _textVertexBufferBack;
_textVertexBufferBack = tempVertexBuffer;Offscreen Gaussian blur and drop shadow dispatches are highly sensitive to parameter fluctuations during keyframe animations or hover transitions. Smooth float radius adjustments (e.g. transitioning from 1.0f to 3.0f) dynamically modify the computed iteration count: $$\text{iterations} = \text{Clamp}(\text{Round}(\text{radius} / 2.5), 1, 8)$$ This causes the rendering loop to alter command-buffer layouts and recreate dynamic bind groups frame-by-frame, creating noticeable micro-stutters.
To stabilize effect execution, we implemented a Snapped Radii Pipeline:
float snappedRadius = MathF.Round(radius * 2f) / 2f;The ProGPU solution is partitioned into modular, highly specialized C# projects. Each project governs a specific layer of the UI, vector, or graphics compilation loops:
| Project | Assembly Name | Core Architectural Responsibility | Key Components & Classes |
|---|---|---|---|
| ProGPU.Backend | ProGPU.Backend.dll | Low-level hardware infrastructure and WebGPU swapchain orchestration. | WgpuContext, Window, Shaders, RenderPipelineCache |
| ProGPU.Compute | ProGPU.Compute.dll | Orchestration of WebGPU GPGPU compute pipelines and parallel filter dispatches. | ComputeAccelerator, ComputeShaders |
| ProGPU.Vector | ProGPU.Vector.dll | Mathematical primitives, Bezier models, path segment parsing, and atlas mapping. | PathGeometry, PathFigure, GpuPathSegment, PathAtlas |
| ProGPU.Text | ProGPU.Text.dll | TrueType Font (TTF) parsing, glyph extraction, word-wrapping, and line layout engines. | TtfFont, GlyphAtlas, TextLayout |
| ProGPU.Scene | ProGPU.Scene.dll | Retained scene-graph visual tree, decoupled layout boundaries, and compositor compiler. | Compositor, ContainerVisual, DrawingVisual, ILayoutNode |
| ProGPU.Layout | ProGPU.Layout.dll | XAML-compatible sizing negotiation lifecycle (Measure / Arrange) and layout panels. | LayoutNode, StackPanel, GridPanel, CanvasPanel |
| ProGPU.WinUI | ProGPU.WinUI.dll | High-level interactive UI control suite layered on top of layout nodes. | Border, Grid, Pivot, RichTextBlock, ScrollViewer, SplitView |
| ProGPU.Virtualization | ProGPU.Virtualization.dll | Dynamic scrolling viewport orchestration and UI virtualization controllers. | VirtualizingPanel, ViewportInfo |
| ProGPU.Samples | ProGPU.Samples.dll | Showcase bootstrap, keyframe and physics animation drivers, diagnostics, and stress-test suites. | Program, AppState, MainWindowController, MotionMarkShowcaseVisual |
ProGPU routes all graphics and compute tasks directly to the GPU using specialized WGSL (WebGPU Shading Language) shaders. The following sections detail their purpose, execution pipelines, and exact implementations.
To support high-quality rendering diagnostics and verify vector structures, ProGPU includes two dedicated diagnostic utilities:
Located in tools/TtfDiag/, this is a generic console tool designed to inspect outline structures, endpoint coordinates, and control points of TrueType fonts. It is especially useful for diagnosing text rendering quality, drop-out artifacts, or glyph parsing inconsistencies.
# Run using the system's Arial font (supplemental) fallback to inspect specific glyphs (e.g. 'G' and 'g')
dotnet run --project tools/TtfDiag -- Arial Gg
# Run with an absolute path to a custom font and custom character sequence
dotnet run --project tools/TtfDiag -- /System/Library/Fonts/Supplemental/Georgia.ttf ABCLocated in tools/DxfDiag/, this is a standalone command-line utility to inspect DXF vector files. It lists all available layouts and layers, prints active layout geometric bounds, recursive block hierarchies, nested insert attributes (tags/values), and detects coordinate outliers exceeding absolute limits ($> 1,000,000$). The complete diagnostic trace is saved to outliers.txt in the local directory.
# Run on a target DXF drawing file to inspect the default active space layout
dotnet run --project tools/DxfDiag -- <path-to-dxf-file>
# Run on a target DXF drawing file and explicitly target a specific layout space (e.g. 'A0')
dotnet run --project tools/DxfDiag -- <path-to-dxf-file> --layout A0ProGPU is designed to act as an embedded high-performance graphics substrate inside standard host XAML frameworks. We provide native integration packages for both Avalonia (ProGPU.Avalonia) and Uno Platform (ProGPU.Uno), allowing developers to overlay low-allocation WebGPU rendering canvases directly inside standard desktop applications.
The integration layer hosts a headless, offscreen WgpuContext and Compositor instance inside a custom control subclass (Control in Avalonia, ContentControl in Uno). WebGPU renders all visual tree and CAD vectors offscreen, which are then blitted directly to the host's screen.
graph TD
subgraph UIThread ["Host UI Thread (Input & Sizing)"]
Size[Sizing Negotiation: Measure & Arrange] --> Input[Pointer Event Capture & Translation]
end
subgraph GPUThread ["GPU & WebGPU Staging Loop"]
Input -->|InputSystem.Inject| WG[WebGPU Core Offscreen Render]
Size -->|Logical Bounds| WG
WG -->|CommandEncoderCopy| ST[Staging Buffer VRAM]
ST -->|Sync MapRead| MP[Mapped CPU Pointer]
MP -->|Direct Pointer Blit| WB[WriteableBitmap 96 DPI]
WB -->|Invalidate / DrawImage| SCR[High-DPI Retina Screen]
end
Due to standard platform-agnostic FFI limitations in wgpu-native, raw WGPUTexture pointers cannot be shared directly with the compositor's graphics context (Metal/D3D) as IOSurfaceRef or id<MTLTexture> handles without writing custom native Rust/C++ bridging wrappers.
To bypass these FFI opaque struct constraints and deliver 100% stable, platform-independent rendering, ProGPU implements a highly optimized Direct Bitmap Blitting pipeline:
using (var locked = _writeableBitmap.Lock())
{
byte* srcBytes = (byte*)mappedPtr;
byte* dstBytes = (byte*)locked.Address;
uint rowBytes = _renderWidth * bytesPerPixel;
for (uint y = 0; y < _renderHeight; y++)
{
byte* srcRow = srcBytes + (y * _bytesPerRow);
byte* dstRow = dstBytes + (y * (uint)locked.RowBytes);
System.Buffer.MemoryCopy(srcRow, dstRow, rowBytes, rowBytes);
}
}On macOS Retina displays (e.g. DpiScale = 2.0), standard platform-specific graphics renderers often apply the display's scaling factor twice when drawing a high-DPI bitmap, blowing up the layout and creating blurry graphics.
ProGPU resolves this double-scaling bug through strict physical-to-logical coordination:
The integration libraries bridge the event-handling loop symmetrically:
InputSystem.InjectMouseMove(new Vector2((float)pos.X, (float)pos.Y));To allow embedded graphics and animation benches to run at their physical display limit, standard timer loops are replaced by self-scheduling graphics dispatchers:
TopLevel.RequestAnimationFrame(OnAnimationTick);To bypass the overhead of copying pixels from VRAM to CPU staging buffers and back to VRAM (double-copy blitting), ProGPU implements a cutting-edge Zero-Copy Shared Texture Rendering Pipeline. This architecture achieves direct GPU-to-GPU memory sharing between the offscreen WebGPU rendering engine and the host UI composition tree.
sequenceDiagram
participant WebGPU as WebGPU Engine
participant OS as OS Shared Resource (IOSurface / D3D11)
participant Avalonia as Avalonia Compositor Tree
participant GPU as physical GPU VRAM
WebGPU->>OS: 1. Render directly to Shared Handle (Zero CPU Copy)
OS->>GPU: 2. Texture contents persist in VRAM
Avalonia->>OS: 3. Import Shared Handle via ICompositionGpuInterop
Avalonia->>GPU: 4. Draw directly from VRAM (Zero Copy / 120 FPS+)
The Zero-Copy pipeline eliminates host CPU copies entirely by allocating a hardware-backed shared OS memory handle directly in C#, wrapping it inside WebGPU as a render target, and importing it into the host visual tree:
| Operating System | Shared Resource Type | Native Handle Reference | Allocation Strategy |
|---|---|---|---|
| macOS | Apple IOSurface | IOSurfaceRef (global handle) | CoreFoundation/AppKit unmanaged dictionary creation |
| Windows | Direct3D11 Shared Texture | DXGI HANDLE (global shared key) | Standalone ID3D11Device with D3D11_RESOURCE_MISC_SHARED |
CoreFoundation and Objective-C runtime P/Invokes are used to construct the surface configuration plist:
Direct COM VTable indexing is utilized to create resources dynamically:
The host control hooks into Avalonia's composition engine during initialization:
var interop = await compositor.TryGetCompositionGpuInterop();var platformHandle = new PlatformHandle(_sharedHandle, _gpuHandleType);
_importedGpuImage = _gpuInterop.ImportImage(platformHandle, properties);_ = _drawingSurface.UpdateAsync(_importedGpuImage);Standard cross-platform wgpu-native bindings do not export helper functions out-of-the-box to wrap arbitrary IOSurfaceRef or shared ID3D11Texture2D handles into WebGPU texture objects. To complete the zero-copy pipeline on the WebGPU side, a small custom native wrapper (written in Rust or C++) must bridge the HAL (Hardware Abstraction Layer) boundary:
// Custom native Rust crate bridging wgpu-core and OS handles
use wgpu_core::hub::Global;
use wgpu_hal::api::{Metal, Dx12};
#[no_mangle]
pub unsafe extern "C" fn wgpuDeviceCreateTextureFromMacIOSurface(
device_ptr: *mut libc::c_void,
iosurface_ptr: *mut libc::c_void,
width: u32,
height: u32
) -> *mut libc::c_void {
let global = &*Global::default();
// 1. Extract raw device representation
let device_id = std::mem::transmute(device_ptr);
// 2. Fetch the Metal device and wrap the IOSurface handle via wgpu_hal
let surface: Metal::Texture = Metal::texture_from_raw(iosurface_ptr as *mut _);
// 3. Register the newly created texture inside the wgpu-core context
let texture_id = global.device_create_texture_from_hal::<Metal>(
device_id,
surface,
width,
height
);
std::mem::transmute(texture_id)
}This bridge allows WebGPU command encoders to bind the texture as a standard RenderPassColorAttachment, completing the zero-copy pipeline.
To achieve VSync-locked rendering (120 FPS+) and completely eliminate UI-thread blocking or frame flickering, ProGPU utilizes a high-performance Asynchronous Double-Buffered Update Loop driven by a Dedicated Background Device Polling Thread.
This architecture guarantees 0% CPU blocking on the main UI thread and prevents read-write VRAM conflicts between the renderer and the host compositor.
sequenceDiagram
participant UI as UI Thread (RenderFrameAsync)
participant BG as Background Polling Thread
participant WGPU as WebGPU Device / Queue
participant Swap as SwapchainImage (Double Buffered)
participant Comp as Avalonia Compositor Thread
UI->>WGPU: 1. Render scene offscreen to WgpuTexture (Image A)
UI->>WGPU: 2. Queue CopyTextureToStagingBuffer
UI->>WGPU: 3. Invoke MapBufferAsync (non-blocking Task)
Note over UI,BG: UI thread yields control immediately
Loop Continuous Polling
BG->>WGPU: 4. wgpuDevicePoll(Device, false) every 2ms
End
WGPU-->>BG: 5. Mapping complete! Trigger MapCallback
BG-->>UI: 6. Complete TaskCompletionSource (Resume UI)
UI->>Swap: 7. CopyMappedToSharedTexture (MemoryCopy / UpdateSubresource)
UI->>WGPU: 8. BufferUnmap
UI->>Comp: 9. UpdateAsync (Swapchain Image A)
Note over UI,Comp: Image A is now bound to Compositor. Swap to Image B.
A dedicated SwapchainImage class encapsulates the graphics assets for a single frame. The host control manages a pool of two swapchain images (SwapchainImage[2]):
private class SwapchainImage : IDisposable
{
public IntPtr SharedHandle;
public ICompositionImportedGpuImage? ImportedImage;
public GpuTexture? WgpuTexture;
public IntPtr StagingBuffer;
public uint StagingBufferSize;
public uint BytesPerRow;
// Windows Specific Direct3D 11 Resources
public IntPtr WinD3DDevice;
public IntPtr WinTexture2D;
}WebGPU asynchronous operations (such as staging buffer mapping) require the device queue event loop to be polled via wgpuDevicePoll. To keep the UI and Avalonia render threads completely unblocked, ProGPU runs a continuous, low-latency background polling thread that executes wgpuDevicePoll every 2 milliseconds:
private void StartPolling()
{
_pollingThread = new Thread(() => {
while (!_pollingCts.Token.IsCancellationRequested) {
wgpuDevicePoll(_wgpuContext.Device, false, null);
Thread.Sleep(2);
}
}) { IsBackground = true, Name = "ProGpuDevicePolling" };
_pollingThread.Start();
}The buffer mapping callback is wrapped in a standard C# TaskCompletionSource<bool>. Calling await MapBufferAsync(...) suspends the rendering task without blocking any CPU execution context. The background polling thread completes the mapping asynchronously, waking up the rendering task instantly:
private Task MapBufferAsync(IntPtr buffer, MapMode mode, nuint size)
{
unsafe {
var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
var handle = GCHandle.Alloc(tcs);
var userData = (void*)GCHandle.ToIntPtr(handle);
_wgpuContext.Wgpu.BufferMapAsync((GpuBuffer*)buffer, mode, 0, size, s_mapCallback, userData);
return tcs.Task;
}
}To comply with the C# compiler constraints that prohibit await operations inside unsafe contexts, ProGPU segregates low-level pointer copying into two dedicated synchronous unsafe helper functions:
// macOS row-by-row IOSurface memory copy
GpuSharingInterop.IOSurfaceLock(image.SharedHandle, 0, null);
void* destPtr = GpuSharingInterop.IOSurfaceGetBaseAddress(image.SharedHandle);
System.Buffer.MemoryCopy(srcRow, destRow, rowBytes, rowBytes);
GpuSharingInterop.IOSurfaceUnlock(image.SharedHandle, 0, null);
// Windows D3D11 UpdateSubresource call via COM VTable index 49
GpuSharingInterop.COMHelper.CallUpdateSubresource(context, image.WinTexture2D, 0, IntPtr.Zero, mappedPtr, image.BytesPerRow, 0);If graphics interop is not supported by the environment (e.g. software rendering, missing drivers, or Linux configurations lacking Vulkan opaque handles), the control gracefully falls back to the Decoupled Render-Thread Blitting Pipeline (Phase 2). This ensures 100% functionality and visual parity across all host configurations!
| Back | FazBrowse Home | New Git URL |