Browse Source

optimize inital setup and fix initial render pass.

pull/7416/head
Dan Walmsley 5 years ago
parent
commit
cd2c6b4859
  1. 137
      src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs

137
src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs

@ -26,8 +26,8 @@ namespace Avalonia.Web.Blazor
private InputHelperInterop _canvasHelper = null!; private InputHelperInterop _canvasHelper = null!;
private ElementReference _htmlCanvas; private ElementReference _htmlCanvas;
private ElementReference _inputElement; private ElementReference _inputElement;
private double _dpi; private double _dpi = 1;
private SKSize _canvasSize; private SKSize _canvasSize = new (100, 100);
private GRContext? _context; private GRContext? _context;
private GRGlInterface? _glInterface; private GRGlInterface? _glInterface;
@ -249,71 +249,55 @@ namespace Avalonia.Web.Blazor
[Parameter(CaptureUnmatchedValues = true)] [Parameter(CaptureUnmatchedValues = true)]
public IReadOnlyDictionary<string, object>? AdditionalAttributes { get; set; } public IReadOnlyDictionary<string, object>? AdditionalAttributes { get; set; }
protected override void OnAfterRender(bool firstRender) protected override async Task OnAfterRenderAsync(bool firstRender)
{ {
if (firstRender) if (firstRender)
{ {
Threading.Dispatcher.UIThread.Post(async () => _inputHelper = await InputHelperInterop.ImportAsync(Js, _inputElement);
_canvasHelper = await InputHelperInterop.ImportAsync(Js, _htmlCanvas);
_inputHelper.Hide();
_canvasHelper.SetCursor("default");
_topLevelImpl.SetCssCursor = x =>
{
_inputHelper.SetCursor(x); //macOS
_canvasHelper.SetCursor(x); //windows
};
Console.WriteLine("starting html canvas setup");
_interop = await SKHtmlCanvasInterop.ImportAsync(Js, _htmlCanvas, OnRenderFrame);
Console.WriteLine("Interop created");
_jsGlInfo = _interop.InitGL();
Console.WriteLine("jsglinfo created - init gl");
// create the SkiaSharp context
if (_context == null)
{ {
_inputHelper = await InputHelperInterop.ImportAsync(Js, _inputElement); Console.WriteLine("create glcontext");
_canvasHelper = await InputHelperInterop.ImportAsync(Js, _htmlCanvas); _glInterface = GRGlInterface.Create();
_context = GRContext.CreateGl(_glInterface);
_inputHelper.Hide();
_canvasHelper.SetCursor("default"); var options = AvaloniaLocator.Current.GetService<SkiaOptions>();
_topLevelImpl.SetCssCursor = x => // bump the default resource cache limit
{ _context.SetResourceCacheLimit(options?.MaxGpuResourceSizeBytes ?? 32 * 1024 * 1024);
_inputHelper.SetCursor(x);//macOS Console.WriteLine("glcontext created and resource limit set");
_canvasHelper.SetCursor(x);//windows }
};
_topLevelImpl.SetSurface(_context, _jsGlInfo, ColorType,
Console.WriteLine("starting html canvas setup"); new PixelSize((int)_canvasSize.Width, (int)_canvasSize.Height), _dpi);
_interop = await SKHtmlCanvasInterop.ImportAsync(Js, _htmlCanvas, OnRenderFrame);
_initialised = true;
Console.WriteLine("Interop created");
_jsGlInfo = _interop.InitGL(); _topLevel.Prepare();
Console.WriteLine("jsglinfo created - init gl"); _topLevel.Renderer.Start();
_sizeWatcher = await SizeWatcherInterop.ImportAsync(Js, _htmlCanvas, OnSizeChanged); Invalidate();
_dpiWatcher = await DpiWatcherInterop.ImportAsync(Js, OnDpiChanged);
_sizeWatcher = await SizeWatcherInterop.ImportAsync(Js, _htmlCanvas, OnSizeChanged);
Console.WriteLine("watchers created."); _dpiWatcher = await DpiWatcherInterop.ImportAsync(Js, OnDpiChanged);
// create the SkiaSharp context
if (_context == null)
{
Console.WriteLine("create glcontext");
_glInterface = GRGlInterface.Create();
_context = GRContext.CreateGl(_glInterface);
var options = AvaloniaLocator.Current.GetService<SkiaOptions>();
// bump the default resource cache limit
_context.SetResourceCacheLimit(options?.MaxGpuResourceSizeBytes ?? 32 * 1024 * 1024);
Console.WriteLine("glcontext created and resource limit set");
}
_topLevelImpl.SetSurface(_context, _jsGlInfo, ColorType,
new PixelSize((int)_canvasSize.Width, (int)_canvasSize.Height), _dpi);
_initialised = true;
_topLevel.Prepare();
_topLevel.Renderer.Start();
// Note: this is technically a hack, but it's a kinda unique use case when
// we want to blit the previous frame
// renderer doesn't have much control over the render target
// we render on the UI thread
// We also don't want to have it as a meaningful public API.
// Therefore we have InternalsVisibleTo hack here.
if (_topLevel.Renderer is DeferredRenderer dr)
{
dr.Render(true);
}
Invalidate();
});
} }
} }
@ -335,16 +319,28 @@ namespace Avalonia.Web.Blazor
_interop.Dispose(); _interop.Dispose();
} }
private void OnDpiChanged(double newDpi) private void ForceBlit()
{ {
_dpi = newDpi; // Note: this is technically a hack, but it's a kinda unique use case when
// we want to blit the previous frame
// renderer doesn't have much control over the render target
// we render on the UI thread
// We also don't want to have it as a meaningful public API.
// Therefore we have InternalsVisibleTo hack here.
_topLevelImpl.SetClientSize(_canvasSize, _dpi);
if (_topLevel.Renderer is DeferredRenderer dr) if (_topLevel.Renderer is DeferredRenderer dr)
{ {
dr.Render(true); dr.Render(true);
} }
}
private void OnDpiChanged(double newDpi)
{
_dpi = newDpi;
_topLevelImpl.SetClientSize(_canvasSize, _dpi);
ForceBlit();
Invalidate(); Invalidate();
} }
@ -357,17 +353,14 @@ namespace Avalonia.Web.Blazor
_topLevelImpl.SetClientSize(_canvasSize, _dpi); _topLevelImpl.SetClientSize(_canvasSize, _dpi);
if (_topLevel.Renderer is DeferredRenderer dr) ForceBlit();
{
dr.Render(true);
}
Invalidate(); Invalidate();
} }
public void Invalidate() public void Invalidate()
{ {
if (!_initialised || _canvasSize.Width <= 0 || _canvasSize.Height <= 0 || _dpi <= 0 || _jsGlInfo == null) if (!_initialised || _jsGlInfo == null)
{ {
Console.WriteLine("invalidate ignored"); Console.WriteLine("invalidate ignored");
return; return;

Loading…
Cancel
Save