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 ElementReference _htmlCanvas;
private ElementReference _inputElement;
private double _dpi;
private SKSize _canvasSize;
private double _dpi = 1;
private SKSize _canvasSize = new (100, 100);
private GRContext? _context;
private GRGlInterface? _glInterface;
@ -249,71 +249,55 @@ namespace Avalonia.Web.Blazor
[Parameter(CaptureUnmatchedValues = true)]
public IReadOnlyDictionary<string, object>? AdditionalAttributes { get; set; }
protected override void OnAfterRender(bool firstRender)
protected override async Task OnAfterRenderAsync(bool 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);
_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");
_sizeWatcher = await SizeWatcherInterop.ImportAsync(Js, _htmlCanvas, OnSizeChanged);
_dpiWatcher = await DpiWatcherInterop.ImportAsync(Js, OnDpiChanged);
Console.WriteLine("watchers created.");
// 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();
});
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();
Invalidate();
_sizeWatcher = await SizeWatcherInterop.ImportAsync(Js, _htmlCanvas, OnSizeChanged);
_dpiWatcher = await DpiWatcherInterop.ImportAsync(Js, OnDpiChanged);
}
}
@ -335,16 +319,28 @@ namespace Avalonia.Web.Blazor
_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)
{
dr.Render(true);
}
}
private void OnDpiChanged(double newDpi)
{
_dpi = newDpi;
_topLevelImpl.SetClientSize(_canvasSize, _dpi);
ForceBlit();
Invalidate();
}
@ -357,17 +353,14 @@ namespace Avalonia.Web.Blazor
_topLevelImpl.SetClientSize(_canvasSize, _dpi);
if (_topLevel.Renderer is DeferredRenderer dr)
{
dr.Render(true);
}
ForceBlit();
Invalidate();
}
public void Invalidate()
{
if (!_initialised || _canvasSize.Width <= 0 || _canvasSize.Height <= 0 || _dpi <= 0 || _jsGlInfo == null)
if (!_initialised || _jsGlInfo == null)
{
Console.WriteLine("invalidate ignored");
return;

Loading…
Cancel
Save