Skip to content

Commit 971464b

Browse files
Copilotphilstopford
andcommitted
Add documentation for viewport performance fixes
Co-authored-by: philstopford <1983851+philstopford@users.noreply.github.com>
1 parent 8c036f3 commit 971464b

File tree

1 file changed

+81
-0
lines changed

1 file changed

+81
-0
lines changed

VIEWPORT_PERFORMANCE_FIX.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Viewport Performance Fix for Linux/GTK
2+
3+
## Problem Statement
4+
The viewport on Linux/GTK was 10-20 seconds slower to update with geometry compared to Windows for the same data.
5+
6+
## Root Cause Analysis
7+
8+
### Issue 1: Async/Await Race Condition (CRITICAL)
9+
The `pUpdateViewport()` method was declared as `async void`, which caused a critical race condition:
10+
11+
```csharp
12+
// BEFORE (BROKEN):
13+
private async void pUpdateViewport() {
14+
// ... async work ...
15+
done_drawing = true;
16+
}
17+
18+
public void updateViewport() {
19+
pUpdateViewport(); // Returns immediately, doesn't wait!
20+
if (done_drawing) { // Always false here - async work not done yet
21+
Surface!.Invalidate(); // NEVER CALLED
22+
}
23+
}
24+
```
25+
26+
**Impact**: The viewport would never invalidate after geometry updates because `done_drawing` was checked before the async work completed. Only timer-based updates worked, causing the perceived 10-20 second delays.
27+
28+
### Issue 2: Inefficient Nested Parallelization
29+
Tessellated polygons used a nested `Parallel.For` loop:
30+
31+
```csharp
32+
// BEFORE (INEFFICIENT):
33+
Parallel.For(0, tessPolyListCount, poly => {
34+
Parallel.For(0, 3, pt => { // Parallelizing 3 iterations!
35+
// Process triangle point
36+
});
37+
});
38+
```
39+
40+
**Impact**: The overhead of spawning threads for just 3 iterations far exceeded any benefit, especially on GTK/Linux where thread scheduling has more overhead.
41+
42+
## Solution
43+
44+
### Fix 1: Proper Async/Await Pattern
45+
```csharp
46+
// AFTER (FIXED):
47+
private async Task pUpdateViewportAsync() {
48+
// ... async work ...
49+
done_drawing = true;
50+
}
51+
52+
public async void updateViewport() {
53+
await pUpdateViewportAsync(); // Actually waits for completion!
54+
if (done_drawing) { // Now true when async work is done
55+
Surface!.Invalidate(); // GETS CALLED
56+
}
57+
}
58+
```
59+
60+
### Fix 2: Sequential Inner Loop
61+
```csharp
62+
// AFTER (OPTIMIZED):
63+
Parallel.For(0, tessPolyListCount, poly => {
64+
for (int pt = 0; pt < 3; pt++) { // Sequential for small iterations
65+
// Process triangle point
66+
}
67+
});
68+
```
69+
70+
## Files Modified
71+
- `Eto/Eto.VeldridSurface/VeldridDriver_Draw.cs` - Fixed async pattern and parallelization
72+
- `Eto/Eto.VeldridSurface/VeldridDriver_Public.cs` - Updated `updateViewport()` to await properly
73+
- `Eto/Eto.VeldridSurface/VeldridDriver_Handlers.cs` - Updated `Clock_Elapsed()` to await properly
74+
75+
## Testing
76+
- All 437 unit tests pass
77+
- No regressions introduced
78+
- GTK test application builds successfully
79+
80+
## Expected Performance Improvement
81+
The viewport should now update immediately after geometry changes on Linux/GTK, matching Windows performance. The 10-20 second delay should be completely eliminated as `Surface.Invalidate()` is now called correctly after geometry processing completes.

0 commit comments

Comments
 (0)