1
- using SkiaSharp ;
2
- using MUX = Microsoft . UI . Xaml ;
3
- using Uno . Foundation . Logging ;
4
- using Windows . Graphics . Display ;
1
+ using System . Diagnostics ;
5
2
using System . Runtime . InteropServices . JavaScript ;
6
- using Uno . UI . Hosting ;
7
- using System . Diagnostics ;
8
- using Uno . UI . Helpers ;
3
+ using System . Threading ;
9
4
using Microsoft . UI . Xaml . Media ;
5
+ using SkiaSharp ;
6
+ using Uno . Foundation . Logging ;
10
7
using Uno . UI . Dispatching ;
8
+ using Uno . UI . Helpers ;
9
+ using Uno . UI . Hosting ;
10
+ using Windows . Graphics . Display ;
11
11
12
12
namespace Uno . UI . Runtime . Skia ;
13
13
@@ -33,6 +33,8 @@ internal partial class BrowserRenderer
33
33
private GRBackendRenderTarget ? _renderTarget ;
34
34
private SKSurface ? _surface ;
35
35
private SKCanvas ? _canvas ;
36
+ private SKPicture ? _picture ;
37
+ private SKPath ? _clipPath ;
36
38
37
39
private SKSizeI ? _lastSize ;
38
40
@@ -60,18 +62,32 @@ private void Initialize()
60
62
_jsInfo = NativeMethods . CreateContext ( this , _nativeSwapChainPanel , WebAssemblyWindowWrapper . Instance ? . CanvasId ?? "invalid" ) ;
61
63
}
62
64
63
- internal void InvalidateRender ( ) => NativeMethods . Invalidate ( _nativeSwapChainPanel ) ;
64
-
65
- private void RenderFrame ( )
65
+ internal void InvalidateRender ( )
66
66
{
67
- using var _ = _fpsHelper . BeginFrame ( ) ;
68
-
69
- if ( _host . RootElement is { } rootElement && ( rootElement . IsArrangeDirtyOrArrangeDirtyPath || rootElement . IsMeasureDirtyOrMeasureDirtyPath ) )
67
+ if ( _host . RootElement is not { } rootElement || ( rootElement . IsArrangeDirtyOrArrangeDirtyPath || rootElement . IsMeasureDirtyOrMeasureDirtyPath ) )
70
68
{
71
- InvalidateRender ( ) ;
69
+ // Try again next tick
70
+ NativeDispatcher . Main . Enqueue ( ( ) => ( ( IXamlRootHost ) this ) . InvalidateRender ( ) ) ;
72
71
return ;
73
72
}
74
73
74
+ var ( picture , path ) = SkiaRenderHelper . RecordPictureAndReturnPath (
75
+ ( int ) ( Microsoft . UI . Xaml . Window . CurrentSafe ! . Bounds . Width ) ,
76
+ ( int ) ( Microsoft . UI . Xaml . Window . CurrentSafe ! . Bounds . Height ) ,
77
+ rootElement . Visual ,
78
+ invertPath : false ) ;
79
+ _host . RootElement ? . XamlRoot ? . InvokeFramePainted ( ) ;
80
+
81
+ Interlocked . Exchange ( ref _picture , picture ) ;
82
+ Interlocked . Exchange ( ref _clipPath , path ) ;
83
+
84
+ NativeMethods . Invalidate ( _nativeSwapChainPanel ) ;
85
+ }
86
+
87
+ private void RenderFrame ( )
88
+ {
89
+ using var _ = _fpsHelper . BeginFrame ( ) ;
90
+
75
91
if ( ! _jsInfo . IsValid )
76
92
{
77
93
Initialize ( ) ;
@@ -134,21 +150,21 @@ private void RenderFrame()
134
150
}
135
151
}
136
152
153
+ var currentPicture = _picture ;
154
+ var currentClipPath = _clipPath ;
155
+
137
156
using ( new SKAutoCanvasRestore ( _canvas , true ) )
138
157
{
139
158
_surface . Canvas . Clear ( SKColors . Transparent ) ;
140
159
_surface . Canvas . Scale ( ( float ) scale ) ;
141
- if ( _host . RootElement ? . Visual is { } rootVisual )
142
- {
143
- var negativePath = SkiaRenderHelper . RenderRootVisualAndReturnNegativePath ( _renderTarget . Width , _renderTarget . Height , rootVisual , _canvas ) ;
144
- _fpsHelper . DrawFps ( _canvas ) ;
145
- // Unlike other skia platforms, on skia/wasm we need to undo the scaling adjustment that happens inside
146
- // RenderRootVisualAndReturnNegativePath since the numbers we get from native are already scaled, so we
147
- // don't need to do our own scaling in RenderRootVisualAndReturnNegativePath.
148
- negativePath . Transform ( SKMatrix . CreateScale ( ( float ) ( 1 / scale ) , ( float ) ( 1 / scale ) ) , negativePath ) ;
149
- BrowserNativeElementHostingExtension . SetSvgClipPathForNativeElementHost ( ! negativePath . IsEmpty ? negativePath . ToSvgPathData ( ) : "" ) ;
150
- _host . RootElement ? . XamlRoot ? . InvokeFramePainted ( ) ;
151
- }
160
+ _surface . Canvas . DrawPicture ( currentPicture ) ;
161
+ _fpsHelper . DrawFps ( _canvas ) ;
162
+
163
+ // Unlike other skia platforms, on skia/wasm we need to undo the scaling adjustment that happens inside
164
+ // RenderRootVisualAndReturnNegativePath since the numbers we get from native are already scaled, so we
165
+ // don't need to do our own scaling in RenderRootVisualAndReturnNegativePath.
166
+ currentClipPath ? . Transform ( SKMatrix . CreateScale ( ( float ) ( 1 / scale ) , ( float ) ( 1 / scale ) ) , currentClipPath ) ;
167
+ BrowserNativeElementHostingExtension . SetSvgClipPathForNativeElementHost ( currentClipPath is not null && ! currentClipPath . IsEmpty ? currentClipPath . ToSvgPathData ( ) : "" ) ;
152
168
}
153
169
154
170
// update the control
0 commit comments