-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
/
RenderWorker.cs
139 lines (122 loc) · 5.37 KB
/
RenderWorker.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.JavaScript;
using System.Threading;
using System.Threading.Tasks;
using Avalonia.Browser.Interop;
namespace Avalonia.Browser.Rendering;
internal partial class RenderWorker
{
[DllImport("*")]
private static extern int pthread_self();
[JSImport("WebRenderTargetRegistry.initializeWorker", AvaloniaModule.MainModuleName)]
private static partial void InitializeRenderTargets();
internal static int WorkerThreadId;
public static Task InitializeAsync()
{
var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
var workerTask = JSWebWorkerClone.RunAsync(async () =>
{
try
{
await AvaloniaModule.ImportMainToCurrentContext();
InitializeRenderTargets();
WorkerThreadId = pthread_self();
BrowserSharedRenderLoop.RenderTimer.StartOnThisThread();
tcs.SetResult();
// Never surrender
await new TaskCompletionSource().Task;
}
catch (Exception e)
{
tcs.SetException(e);
}
});
workerTask.ContinueWith(_ =>
{
if (workerTask.IsFaulted)
tcs.TrySetException(workerTask.Exception);
});
return tcs.Task;
}
public static class JSWebWorkerClone
{
private static readonly MethodInfo _setExtLoop;
private static readonly MethodInfo _intallInterop;
[DynamicDependency(DynamicallyAccessedMemberTypes.All, "System.Runtime.InteropServices.JavaScript.JSSynchronizationContext",
"System.Runtime.InteropServices.JavaScript")]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, "System.Runtime.InteropServices.JavaScript.JSHostImplementation",
"System.Runtime.InteropServices.JavaScript")]
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Private runtime API")]
[UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Private runtime API")]
static JSWebWorkerClone()
{
var syncContext = typeof(System.Runtime.InteropServices.JavaScript.JSHost)
.Assembly!.GetType("System.Runtime.InteropServices.JavaScript.JSSynchronizationContext")!;
var hostImpl = typeof(System.Runtime.InteropServices.JavaScript.JSHost)
.Assembly!.GetType("System.Runtime.InteropServices.JavaScript.JSHostImplementation")!;
_setExtLoop = hostImpl.GetMethod("SetHasExternalEventLoop")!;
_intallInterop = syncContext.GetMethod("InstallWebWorkerInterop")!;
}
public static Task RunAsync(Func<Task> run)
{
var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
var th = new Thread(_ =>
{
_intallInterop.Invoke(null, [false, CancellationToken.None]);
try
{
run().ContinueWith(t =>
{
if (t.IsFaulted)
tcs.TrySetException(t.Exception);
else if (t.IsCanceled)
tcs.TrySetCanceled();
else
tcs.TrySetResult();
});
}
catch(Exception e)
{
tcs.TrySetException(e);
}
})
{
Name = "Manual JS worker"
};
_setExtLoop.Invoke(null, [th]);
#pragma warning disable CA1416
th.Start();
#pragma warning restore CA1416
return tcs.Task;
}
}
// TODO: Use this class instead of JSWebWorkerClone once https://github.com/dotnet/runtime/issues/102010 is fixed
class JSWebWorkerWrapper
{
[DynamicDependency(DynamicallyAccessedMemberTypes.PublicMethods, "System.Runtime.InteropServices.JavaScript.JSWebWorker",
"System.Runtime.InteropServices.JavaScript")]
[UnconditionalSuppressMessage("Trimming",
"IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code",
Justification = "Private runtime API")]
static JSWebWorkerWrapper()
{
var type = typeof(System.Runtime.InteropServices.JavaScript.JSHost)
.Assembly!.GetType("System.Runtime.InteropServices.JavaScript.JSWebWorker");
#pragma warning disable IL2075
var m = type!
.GetMethods(BindingFlags.Static | BindingFlags.Public
).First(m => m.Name == "RunAsync"
&& m.ReturnType == typeof(Task)
&& m.GetParameters() is { } parameters
&& parameters.Length == 1
&& parameters[0].ParameterType == typeof(Func<Task>));
#pragma warning restore IL2075
RunAsync = (Func<Func<Task>, Task>) Delegate.CreateDelegate(typeof(Func<Func<Task>, Task>), m);
}
public static Func<Func<Task>, Task> RunAsync { get; set; }
}
}