Browse Source

WIP

feature/wmt
Nikita Tsukanov 2 years ago
parent
commit
7b7f2f2ea8
  1. 5
      src/Browser/Avalonia.Browser/BrowserAppBuilder.cs
  2. 6
      src/Browser/Avalonia.Browser/Interop/AvaloniaModule.cs
  3. 21
      src/Browser/Avalonia.Browser/Rendering/BrowserRenderTimer.cs
  4. 77
      src/Browser/Avalonia.Browser/Rendering/RenderWorker.cs
  5. 1
      src/Browser/Avalonia.Browser/WindowingPlatform.cs
  6. 4
      src/Browser/Avalonia.Browser/webapp/modules/avalonia/timer.ts

5
src/Browser/Avalonia.Browser/BrowserAppBuilder.cs

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Avalonia.Browser.Interop;
using Avalonia.Browser.Rendering;
using Avalonia.Metadata;
namespace Avalonia.Browser;
@ -109,6 +110,10 @@ public static class BrowserAppBuilder
AvaloniaLocator.CurrentMutable.Bind<BrowserPlatformOptions>().ToConstant(options);
await AvaloniaModule.ImportMain();
if (BrowserWindowingPlatform.IsThreadingEnabled)
{
await RenderWorker.InitializeAsync();
}
if (builder.WindowingSubsystemInitializer is null)
{

6
src/Browser/Avalonia.Browser/Interop/AvaloniaModule.cs

@ -6,11 +6,13 @@ namespace Avalonia.Browser.Interop;
internal static partial class AvaloniaModule
{
private static readonly Lazy<Task> s_importMain = new(() =>
private static readonly Lazy<Task> s_importMain = new(ImportMainToCurrentContext);
public static Task ImportMainToCurrentContext()
{
var options = AvaloniaLocator.Current.GetService<BrowserPlatformOptions>() ?? new BrowserPlatformOptions();
return JSHost.ImportAsync(MainModuleName, options.FrameworkAssetPathResolver!("avalonia.js"));
});
}
private static readonly Lazy<Task> s_importStorage = new(() =>
{

21
src/Browser/Avalonia.Browser/Rendering/BrowserRenderTimer.cs

@ -22,16 +22,8 @@ internal class BrowserRenderTimer : IRenderTimer
{
add
{
if (!_started)
{
_started = true;
if (BrowserWindowingPlatform.IsThreadingEnabled)
{
}
else
TimerHelper.RunAnimationFrames(RenderFrameCallback);
}
if (!BrowserWindowingPlatform.IsThreadingEnabled)
StartOnThisThread();
_tick += value;
}
@ -41,6 +33,15 @@ internal class BrowserRenderTimer : IRenderTimer
}
}
public void StartOnThisThread()
{
if (!_started)
{
_started = true;
TimerHelper.RunAnimationFrames(RenderFrameCallback);
}
}
private bool RenderFrameCallback(double timestamp)
{
if (_tick is { } tick)

77
src/Browser/Avalonia.Browser/Rendering/RenderWorker.cs

@ -1,6 +1,81 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.JavaScript;
using System.Threading.Tasks;
using Avalonia.Browser.Interop;
namespace Avalonia.Browser.Rendering;
internal class RenderWorker
internal partial class RenderWorker
{
[DllImport("*")]
private static extern int pthread_self();
[JSImport("WebRenderTargetRegistry.initializeWorker", AvaloniaModule.MainModuleName)]
private static partial void InitializeRenderTargets();
public static int WorkerThreadId;
public static Task InitializeAsync()
{
var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
var workerTask = JSWebWorkerWrapper.RunAsync(async () =>
{
try
{
await AvaloniaModule.ImportMainToCurrentContext();
InitializeRenderTargets();
WorkerThreadId = pthread_self();
BrowserCompositor.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;
}
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; }
}
}

1
src/Browser/Avalonia.Browser/WindowingPlatform.cs

@ -65,7 +65,6 @@ internal class BrowserWindowingPlatform : IWindowingPlatform
.Bind<IKeyboardDevice>().ToConstant(s_keyboard)
.Bind<IPlatformSettings>().ToSingleton<BrowserPlatformSettings>()
.Bind<IDispatcherImpl>().ToSingleton<BrowserDispatcherImpl>()
.Bind<IRenderTimer>().ToConstant(ManualTriggerRenderTimer.Instance)
.Bind<IWindowingPlatform>().ToConstant(instance)
.Bind<IPlatformGraphics>().ToConstant(new BrowserSkiaGraphics())
.Bind<IPlatformIconLoader>().ToSingleton<IconLoaderStub>()

4
src/Browser/Avalonia.Browser/webapp/modules/avalonia/timer.ts

@ -3,10 +3,10 @@ export class TimerHelper {
function render(time: number) {
const next = renderFrameCallback(time);
if (next) {
window.requestAnimationFrame(render);
self.requestAnimationFrame(render);
}
}
window.requestAnimationFrame(render);
self.requestAnimationFrame(render);
}
}

Loading…
Cancel
Save